From 8d80d61d2763acb17ef1875fc1dbf0bf173fe907 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 7 Sep 2026 09:44:21 +0200 Subject: [PATCH 01/81] Added assigment to lists.md lesson --- curriculum/05-data-structures/01-list.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/curriculum/05-data-structures/01-list.md b/curriculum/05-data-structures/01-list.md index 64d3e43..1f82310 100644 --- a/curriculum/05-data-structures/01-list.md +++ b/curriculum/05-data-structures/01-list.md @@ -160,7 +160,26 @@ Learn more about Python Lists from these resources: Complete [Exercise 05 — The Cozy Bakery Inventory](#) to practice list creation, indexing, modification, and using python documentation to solve list tasks. ## Assignment {#assignment} -**Todo** +1. Replace `item_name`, `item_price` and `item_stock` static values with an empty list. +2. In *infinite loop* ask the user to fill up the inventory by typing in a name, price and stock level of item. + * If user types **empty string**, break out of the loop and continue with program execution. + * User should enter all of the information on the same line. Use `.split()` method on the inputed string to catch all information needed. **Do not forget** to cast `price` to `float` and `stock` to `integer`. + * Append every information to their own respective list. +3. Display the inventory by using `zip()` function and combining all three lists to display items one by one. +4. Create variable `order` and assign it an empty list. +5. Create another *infinite loop* and inside the loop ask the user to enter the name of the item he wants to buy. + * If user enters empty string, break out of the loop. + * If the item user entered is in the `item_name` list, find its index position and assign it to variable, otherwise inform the user that there is no such item at the moment, and **continue** with next iteration of loop + * When you have an index of the item user asked, ask the user to enter quantity of the items. Check if entered item quantity is not bigger then actual item stock and if it is, tell the user that we do not have that many items in stock, then **continue** with new iteration. + * If we have the item and have enough of stock, add the total for item (item price multiplied by quantity) to `order` list. + * Decrease the stock number of items by the quantity ammount and if item stock reaches 0, remove the item (and its relevant info) from the inventory lists. +6. Calculate the total by adding all the numbers in `order` list using `sum()` function and calculate whether to give 10% discount (if `total > 100`). +7. Print out the final receipt in the following format: + ``` + Your total is: $ + ``` +8. Print the inventory after shopping. +9. Make sure your application works correctly, commit the changes and push your code to Github. ## What's Next {#next-lesson} Lists are ordered and mutable, which makes them ideal for collections that grow or change over time. But what if you need an ordered collection that **cannot** be modified once created? From 3314b18dc6856aadd993f16099720d4c8043abe2 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 7 Sep 2026 09:47:00 +0200 Subject: [PATCH 02/81] Changed assigment in lesson 03-user-input to better follow the storyline --- .../03-user-input-and-conditionals.md | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/curriculum/04-python-foundations/03-user-input-and-conditionals.md b/curriculum/04-python-foundations/03-user-input-and-conditionals.md index 1352303..0f2a698 100644 --- a/curriculum/04-python-foundations/03-user-input-and-conditionals.md +++ b/curriculum/04-python-foundations/03-user-input-and-conditionals.md @@ -94,20 +94,15 @@ Now that you know how to get user input and branch your program using conditiona **Goal:** use `input()` to collect user choices, cast strings to numbers, and use conditional logic to apply discounts and stock checks. -1. Open `main.py` file in our `simple-python-shop` project directory. -2. Add a new variable `item_stock` and set it to some integer -3. Interactive input: - * Ask the user for desired `item_quantity` using `input()`. **Don't forget** to cast the string to integer ! -4. Stock & Availability Check - * If `item_quantity` is less or equal to `0` print an error message: `Invalid quantity ordered` - * If `item_quantity` is greater then `item_stock` print `Sorry, we do not have enough stock.` -5. Dynamic discount (conditionals) - * Calculate the total (you should have this from the last lesson) - * If `total` is over `100` apply a **10%** discount (`total * 0.90`) and print: `Discount applied: 10%` - * Otherwise print: `No discount applied` -6. Receipt Output - * Output the final receipt showing item name, quantity, applied discount state, and final amount due. -7. Commit and push your updated code to Github. +Open `main.py` in your `simple-python-shop` project. +1. Set `item_quantity` to `0` as its initial value and remove `item_price` variable. +2. Use a `while` loop to repeatedly prompt the user for an item price. + * If the price entered is less then 0, print message saying `Invalid price, must be positive`, and skipping the rest of the iteration code, asking user again to enter the price. + * Otherwise check if the price entered is 0 and if so, break out of the loop. + * Otherwise, check if `item_stock - item_quantity` is more than `1` and if not, break out of the loop, informing the user we are out of stock. + * Otherwise, add the price user entered to `total` and increment `item_quantity` by 1. +3. When the loop finishes, determine if the `total` can have a discount and print out the final receipt. +4. Make sure your program works, then commit and push your code ## Deepen Your Knowledge * Learn more about [Indentation in Python](https://realpython.com/ref/glossary/indentation/) from this **Real Python** article From 5a8276cd3ca7596a32afea9a52ee59f110bf619e Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 7 Sep 2026 09:49:07 +0200 Subject: [PATCH 03/81] Changed assigment in lesson 02-math-string-ops to better follow storyline --- .../02-math-stringops-comparisons.md | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/curriculum/04-python-foundations/02-math-stringops-comparisons.md b/curriculum/04-python-foundations/02-math-stringops-comparisons.md index 5564b2a..15fcc55 100644 --- a/curriculum/04-python-foundations/02-math-stringops-comparisons.md +++ b/curriculum/04-python-foundations/02-math-stringops-comparisons.md @@ -215,28 +215,24 @@ print(not True) # False Try to solve [excercise-3](https://github.com/ThePythonLedger/python-exercises/tree/main/exercises%2Ffoundations%2F03_math_and_comparisons) for better understanding. ## Assignment -In the last assignment we have declared our shop variables and printed the inventory. In this one you are tasked with: -1. Open your code editor in your last project directory `simple-python-shop` -2. Open `main.py` file we have been working on -3. Standardize your strings: - * Convert `shop_name` to **uppercase** (e.g., `MERLIN SHOP`) - * Convert item name to **titlecase** (e.g., `Excalibur`) -4. Calculate the checkout price: - * Create variable `total` by multiplying `item_price` and `item_quantity` -5. Comparison checks: - * Create a boolean `is_large_order` that evaluates whether `item_quantity` is greater then or equal to `3`. -6. Update your output to use **f-string** : - ``` - Welcome to MERLIN SHOP - -------------------------------- - Item: Excalibur - Purchased: 3 x 67.20 - Total: $201.60 - Large Order: True - -------------------------------- - Thank you for your purchase ! - ``` -7. Commit your changes with `git` and push to Github +Now that you know how to get user input and branch your program using conditional logic (`if`, `elif`, `else`) the code can move away from hardcoded values and become interactive. + +**Goal:** use `input()` to collect user choices, cast strings to numbers, and use conditional logic to apply discounts and stock checks. + +1. Open `main.py` file in our `simple-python-shop` project directory. +2. Add a new variable `item_stock` and set it to some integer +3. Interactive input: + * Ask the user for desired `item_quantity` using `input()`. **Don't forget** to cast the string to integer ! +4. Stock & Availability Check + * If `item_quantity` is less or equal to `0` print an error message: `Invalid quantity ordered` + * If `item_quantity` is greater then `item_stock` print `Sorry, we do not have enough stock.` +5. Dynamic discount (conditionals) + * Calculate the total (you should have this from the last lesson) + * If `total` is over `100` apply a **10%** discount (`total * 0.90`) and print: `Discount applied: 10%` + * Otherwise print: `No discount applied` +6. Receipt Output + * Output the final receipt showing item name, quantity, applied discount state, and final amount due. +7. Commit and push your updated code to Github. ## Deepen Your Knowledge 1. Learn more about [Basic math in Python](https://cs.stanford.edu/people/nick/py/python-math.html#math) from article in **Stanford University**, covering all the topics in this lesson but in a different style and a bit more. From 29373ffff0c27eb40e05bef788ec2b61d15bba56 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 7 Sep 2026 09:55:43 +0200 Subject: [PATCH 04/81] Fixed assigments due to mistake in copy-paste --- .../01-output-variable-datatypes.md | 2 +- .../02-math-stringops-comparisons.md | 40 ++++++++++--------- .../03-user-input-and-conditionals.md | 23 ++++++----- curriculum/04-python-foundations/04-loops.md | 8 ++-- 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/curriculum/04-python-foundations/01-output-variable-datatypes.md b/curriculum/04-python-foundations/01-output-variable-datatypes.md index d794ab4..be93b37 100644 --- a/curriculum/04-python-foundations/01-output-variable-datatypes.md +++ b/curriculum/04-python-foundations/01-output-variable-datatypes.md @@ -185,7 +185,7 @@ You will need to do this assignment on your own machine. Item price: $67.2 Item available: True ``` -7. Make sure your program works as expected then create a repository and push your code to github +7. Make sure your program works as expected then create a repository and push your code to Github. ## Deepen Your Knowlege Go through these articles to deepen your knowlege about the topics covered in this lesson. diff --git a/curriculum/04-python-foundations/02-math-stringops-comparisons.md b/curriculum/04-python-foundations/02-math-stringops-comparisons.md index 15fcc55..5c8ffff 100644 --- a/curriculum/04-python-foundations/02-math-stringops-comparisons.md +++ b/curriculum/04-python-foundations/02-math-stringops-comparisons.md @@ -215,24 +215,28 @@ print(not True) # False Try to solve [excercise-3](https://github.com/ThePythonLedger/python-exercises/tree/main/exercises%2Ffoundations%2F03_math_and_comparisons) for better understanding. ## Assignment -Now that you know how to get user input and branch your program using conditional logic (`if`, `elif`, `else`) the code can move away from hardcoded values and become interactive. - -**Goal:** use `input()` to collect user choices, cast strings to numbers, and use conditional logic to apply discounts and stock checks. - -1. Open `main.py` file in our `simple-python-shop` project directory. -2. Add a new variable `item_stock` and set it to some integer -3. Interactive input: - * Ask the user for desired `item_quantity` using `input()`. **Don't forget** to cast the string to integer ! -4. Stock & Availability Check - * If `item_quantity` is less or equal to `0` print an error message: `Invalid quantity ordered` - * If `item_quantity` is greater then `item_stock` print `Sorry, we do not have enough stock.` -5. Dynamic discount (conditionals) - * Calculate the total (you should have this from the last lesson) - * If `total` is over `100` apply a **10%** discount (`total * 0.90`) and print: `Discount applied: 10%` - * Otherwise print: `No discount applied` -6. Receipt Output - * Output the final receipt showing item name, quantity, applied discount state, and final amount due. -7. Commit and push your updated code to Github. +In the last assignment we have declared our shop variables and printed the inventory. In this one you are tasked with: +1. Open your code editor in your last project directory `simple-python-shop` +2. Open `main.py` file we have been working on +3. Standardize your strings: + * Convert `shop_name` to **uppercase** (e.g., `MERLIN SHOP`) + * Convert item name to **titlecase** (e.g., `Excalibur`) +4. Calculate the checkout price: + * Create variable `total` by multiplying `item_price` and `item_quantity` +5. Comparison checks: + * Create a boolean `is_large_order` that evaluates whether `item_quantity` is greater then or equal to `3`. +6. Update your output to use **f-string** : + ``` + Welcome to MERLIN SHOP + -------------------------------- + Item: Excalibur + Purchased: 3 x 67.20 + Total: $201.60 + Large Order: True + -------------------------------- + Thank you for your purchase ! + ``` +7. Commit your changes with `git` and push to Github. ## Deepen Your Knowledge 1. Learn more about [Basic math in Python](https://cs.stanford.edu/people/nick/py/python-math.html#math) from article in **Stanford University**, covering all the topics in this lesson but in a different style and a bit more. diff --git a/curriculum/04-python-foundations/03-user-input-and-conditionals.md b/curriculum/04-python-foundations/03-user-input-and-conditionals.md index 0f2a698..1352303 100644 --- a/curriculum/04-python-foundations/03-user-input-and-conditionals.md +++ b/curriculum/04-python-foundations/03-user-input-and-conditionals.md @@ -94,15 +94,20 @@ Now that you know how to get user input and branch your program using conditiona **Goal:** use `input()` to collect user choices, cast strings to numbers, and use conditional logic to apply discounts and stock checks. -Open `main.py` in your `simple-python-shop` project. -1. Set `item_quantity` to `0` as its initial value and remove `item_price` variable. -2. Use a `while` loop to repeatedly prompt the user for an item price. - * If the price entered is less then 0, print message saying `Invalid price, must be positive`, and skipping the rest of the iteration code, asking user again to enter the price. - * Otherwise check if the price entered is 0 and if so, break out of the loop. - * Otherwise, check if `item_stock - item_quantity` is more than `1` and if not, break out of the loop, informing the user we are out of stock. - * Otherwise, add the price user entered to `total` and increment `item_quantity` by 1. -3. When the loop finishes, determine if the `total` can have a discount and print out the final receipt. -4. Make sure your program works, then commit and push your code +1. Open `main.py` file in our `simple-python-shop` project directory. +2. Add a new variable `item_stock` and set it to some integer +3. Interactive input: + * Ask the user for desired `item_quantity` using `input()`. **Don't forget** to cast the string to integer ! +4. Stock & Availability Check + * If `item_quantity` is less or equal to `0` print an error message: `Invalid quantity ordered` + * If `item_quantity` is greater then `item_stock` print `Sorry, we do not have enough stock.` +5. Dynamic discount (conditionals) + * Calculate the total (you should have this from the last lesson) + * If `total` is over `100` apply a **10%** discount (`total * 0.90`) and print: `Discount applied: 10%` + * Otherwise print: `No discount applied` +6. Receipt Output + * Output the final receipt showing item name, quantity, applied discount state, and final amount due. +7. Commit and push your updated code to Github. ## Deepen Your Knowledge * Learn more about [Indentation in Python](https://realpython.com/ref/glossary/indentation/) from this **Real Python** article diff --git a/curriculum/04-python-foundations/04-loops.md b/curriculum/04-python-foundations/04-loops.md index 4489eab..c3f5ac7 100644 --- a/curriculum/04-python-foundations/04-loops.md +++ b/curriculum/04-python-foundations/04-loops.md @@ -122,10 +122,12 @@ These statements `break` and `continue` work only in loops. If you try to use th ## Assigment 1. Open `main.py` in your `simple-python-shop` project. -2. Create a new variable named `item_count` and set it to `0` as its initial value. +2. Set `item_quantity` to `0` as its initial value and remove `item_price` variable. 3. Use a `while` loop to repeatedly prompt the user for an item price. - * If the price entered is 0 break out of the loop - * Otherwise, add the price user entered to `total` and increment `item_count` by 1. + * If the price entered is less then 0, print message saying `Invalid price, must be positive`, and skipping the rest of the iteration code, asking user again to enter the price. + * Otherwise check if the price entered is 0 and if so, break out of the loop. + * Otherwise, check if `item_stock - item_quantity` is more than `1` and if not, break out of the loop, informing the user we are out of stock. + * Otherwise, add the price user entered to `total` and increment `item_quantity` by 1. 4. When the loop finishes, determine if the `total` can have a discount and print out the final receipt. 5. Make sure your program works, then commit and push your code From d72917c7b06e5424d3a6bcb5f16a2b0ba7c839e0 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 7 Sep 2026 11:32:55 +0200 Subject: [PATCH 05/81] Updated Learn More resources --- curriculum/05-data-structures/01-list.md | 10 ++++------ curriculum/05-data-structures/02-tuple.md | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/curriculum/05-data-structures/01-list.md b/curriculum/05-data-structures/01-list.md index 1f82310..97da206 100644 --- a/curriculum/05-data-structures/01-list.md +++ b/curriculum/05-data-structures/01-list.md @@ -148,16 +148,14 @@ for item in a: This is very useful as we often need to work with specific elements from the list. :::explore[Learn more about Python lists] - Learn more about Python Lists from these resources: -* [Google for Education - Python Lists](https://developers.google.com/edu/python/lists) -* [Official Python Documentation on Lists](https://docs.python.org/3/library/stdtypes.html#typesseq-list) -* [Official Python Documentation on Data Structures - more on Lists](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists) - +* Learn about `zip()` function from [zip() function - RealPython](https://realpython.com/ref/builtin-functions/zip/) and [zip() function - official Python Documentation](https://docs.python.org/3.3/library/functions.html#zip) that allows for combining of multiple lists (or other iterables as we will see later) by producing **tuples** (we cover these in the next lesson) +* Learn about `.sort()` method from [official Python Documentation](https://docs.python.org/3/library/stdtypes.html#list.sort) which is very useful in sorting lists in-place. Sorting iterables is a very useful tehnique and there are multiple arguments and ways to sort iterables in Python. Be sure to read this [Sorting Tehniques - official Python documentation](https://docs.python.org/3/howto/sorting.html) to familiarize yourself with tehniques used. +* Go thrue all the available methods on the lists in [More on Lists - official Python documentation](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists), as these will come in handy when working on your projects. You do not need to remember them all, but just read thrue them and their intended purpouse so you will know what is out there. ::: ## Exercise -Complete [Exercise 05 — The Cozy Bakery Inventory](#) to practice list creation, indexing, modification, and using python documentation to solve list tasks. +Complete [[TODO] Exercise 05 — The Cozy Bakery Inventory](#) to practice list creation, indexing, modification, and using python documentation to solve list tasks. ## Assignment {#assignment} 1. Replace `item_name`, `item_price` and `item_stock` static values with an empty list. diff --git a/curriculum/05-data-structures/02-tuple.md b/curriculum/05-data-structures/02-tuple.md index d97d13e..022cac4 100644 --- a/curriculum/05-data-structures/02-tuple.md +++ b/curriculum/05-data-structures/02-tuple.md @@ -7,7 +7,6 @@ lesson: true isDraft: true --- # Tuple -## Introduction {#introduction} Tuple is an ordered and immutable collection data structure. **Ordered** meaning it keeps the order of elements in which they are inserted, and **immutable** means that once the tuple is created it cannot change, and you cannot add or remove elements from it. ## Lesson Overview {#overview} @@ -39,7 +38,7 @@ print(f"First element: {a[0]} - Last element: {a[-1]}") ``` ## Useful methods -Unlike functions, as we cannot modify tuples, we don't have a lot of methods available to us, but we will list a few. +Unlike lists, as we cannot modify tuples, we don't have a lot of methods available to us, but we will list a few. * `count()` - returns the number of times a specified value appears in tuple. ```python interactive numbers = (1, 2, 3, 3, 3, 4, 5) @@ -52,6 +51,7 @@ Unlike functions, as we cannot modify tuples, we don't have a lot of methods ava ``` :::explore[Learn more about Python Tuples] +Read these resources to learn more about tuples in Python: * [Python built-in types: tuples from RealPython](https://realpython.com/ref/builtin-types/tuple/) * [Tuples and Sequences from official Python documentation](https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences) ::: From 48a2aa554b12333cabd0849afa9ae8b09372d4b1 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Thu, 10 Sep 2026 19:30:45 +0200 Subject: [PATCH 06/81] Added assigment and closing words to tuples lesson --- curriculum/05-data-structures/01-list.md | 19 ++++++++++--------- curriculum/05-data-structures/02-tuple.md | 17 +++++++++++++++-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/curriculum/05-data-structures/01-list.md b/curriculum/05-data-structures/01-list.md index 97da206..013a0d0 100644 --- a/curriculum/05-data-structures/01-list.md +++ b/curriculum/05-data-structures/01-list.md @@ -158,26 +158,27 @@ Learn more about Python Lists from these resources: Complete [[TODO] Exercise 05 — The Cozy Bakery Inventory](#) to practice list creation, indexing, modification, and using python documentation to solve list tasks. ## Assignment {#assignment} -1. Replace `item_name`, `item_price` and `item_stock` static values with an empty list. -2. In *infinite loop* ask the user to fill up the inventory by typing in a name, price and stock level of item. +1. Open `main.py` file in our `simple-python-shop` directory +2. Replace `item_name`, `item_price` and `item_stock` static values with an empty list. +3. In *infinite loop* ask the user to fill up the inventory by typing in a name, price and stock level of item. * If user types **empty string**, break out of the loop and continue with program execution. * User should enter all of the information on the same line. Use `.split()` method on the inputed string to catch all information needed. **Do not forget** to cast `price` to `float` and `stock` to `integer`. * Append every information to their own respective list. -3. Display the inventory by using `zip()` function and combining all three lists to display items one by one. -4. Create variable `order` and assign it an empty list. -5. Create another *infinite loop* and inside the loop ask the user to enter the name of the item he wants to buy. +4. Display the inventory by using `zip()` function and combining all three lists to display items one by one. +5. Create variable `order` and assign it an empty list. +6. Create another *infinite loop* and inside the loop ask the user to enter the name of the item he wants to buy. * If user enters empty string, break out of the loop. * If the item user entered is in the `item_name` list, find its index position and assign it to variable, otherwise inform the user that there is no such item at the moment, and **continue** with next iteration of loop * When you have an index of the item user asked, ask the user to enter quantity of the items. Check if entered item quantity is not bigger then actual item stock and if it is, tell the user that we do not have that many items in stock, then **continue** with new iteration. * If we have the item and have enough of stock, add the total for item (item price multiplied by quantity) to `order` list. * Decrease the stock number of items by the quantity ammount and if item stock reaches 0, remove the item (and its relevant info) from the inventory lists. -6. Calculate the total by adding all the numbers in `order` list using `sum()` function and calculate whether to give 10% discount (if `total > 100`). -7. Print out the final receipt in the following format: +7. Calculate the total by adding all the numbers in `order` list using `sum()` function and calculate whether to give 10% discount (if `total > 100`). +8. Print out the final receipt in the following format: ``` Your total is: $ ``` -8. Print the inventory after shopping. -9. Make sure your application works correctly, commit the changes and push your code to Github. +9. Print the inventory after shopping. +10. Make sure your application works correctly, commit the changes and push your code to Github. ## What's Next {#next-lesson} Lists are ordered and mutable, which makes them ideal for collections that grow or change over time. But what if you need an ordered collection that **cannot** be modified once created? diff --git a/curriculum/05-data-structures/02-tuple.md b/curriculum/05-data-structures/02-tuple.md index 022cac4..9ff40f0 100644 --- a/curriculum/05-data-structures/02-tuple.md +++ b/curriculum/05-data-structures/02-tuple.md @@ -56,8 +56,21 @@ Read these resources to learn more about tuples in Python: * [Tuples and Sequences from official Python documentation](https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences) ::: +## Exercise +Complete [[TODO] Exercise 06 — WorkingTitle](#) to practice tuples. + ## Assignment {#assignment} -**Todo** +Using lists to separatly hold multiple related values is brittle and will break if you do not pay attention to all lists containing data. In this assigment we will deal with those issues by using tuples. + +1. Open our `main.py` file we have been working on +2. Create a new empty list called `inventory`. This will hold tuples of related data `(product_name, product_price, product_stock)`. +3. Delete previusly defined `item_name`, `item_price` and `item_stock` variables, we wont need them anymore. +4. Just like before, in **infinite loop**, first check if the input is an *empty string* and if it is, break out of the loop, otherwise get the users input containing *name*, *price* and *stock* in a single line, then split the line using `split()` method to get a list of inputed data. +5. Instead of appending each data to their own list, create a tuple called `item` containing `name`, `price` and `stock` in that particular order and append that to our `inventory` list we declared earlier. Print out each `inventory` element using `for` loop. +6. On to customer ordering items now. Keep `order` list and instead of storing only totals for each item, we will now store `item_name`, `item_quantity` and `line_total` in **tuple** called `line_item` and append that to our `order` list so our shop can better keep track of the orders. **Keep in mind** - tuples are *immutable* which means that you will have to reduce `stock` of the item by replacing entire tuple with new `stock` value. +7. Same as before, calculate the `total` for all the items bought, apply a 10% discount if the `total` is over 100. +8. In the end, print out the inventory, to make sure that the items are actually removed once bought. +9. Make sure your program runs, then commit the changes and push to Github ## What's Next {#next-lesson} -**Todo** \ No newline at end of file +Now that you have seen data structures that can contain duplicates, it's time to meet **set** - a unique data structure that does not allows for duplicates. \ No newline at end of file From 519f228a34c96a9004bec50d3b1c15b2d276043e Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Thu, 10 Sep 2026 20:14:40 +0200 Subject: [PATCH 07/81] Added assigment for lesson on sets --- curriculum/05-data-structures/03-set.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/curriculum/05-data-structures/03-set.md b/curriculum/05-data-structures/03-set.md index e172981..1fbf56b 100644 --- a/curriculum/05-data-structures/03-set.md +++ b/curriculum/05-data-structures/03-set.md @@ -78,8 +78,16 @@ Learn more about sets in these materials: * [Python data structures: set from official Python documentation](https://docs.python.org/3/tutorial/datastructures.html#sets) ::: +## Exercise +Complete [[TODO] Exercise 07 — WorkingTitle](#) to practice sets. + ## Assignment {#assignment} -**Todo** +In this assigment our task is simple one. We need to track distinct *unsold* items so we can better prepare for the next day in our little shop. + +1. Open `main.py` file we have been working on. +2. Define a set for all **sold items** (`item[0]` of element in `order` list) and define a set of **all inventory items** (`item[0]` of element in `inventory` list) - you can use set coprehension to do this in one line or use a for loop to iterate over each item in the lists. +3. Create a variable `unsold_items` and set its value to be `sold_items` substracted from `all_inventory_items` +4. Print out items that did not have a sale today. ## What's Next {#next-lesson} -**Todo** \ No newline at end of file +Now that we covered index based data structures, it's time to meet **dictionary** which is unique in its *key-value* approach and is probably most used data structure (besides *lists*). \ No newline at end of file From 9c0f4aa40fb6dd8461c2b49cd63e5faa048f33e3 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Thu, 10 Sep 2026 21:12:55 +0200 Subject: [PATCH 08/81] Fixed assigment in set lesson and added assigment to dictionary lesson --- curriculum/05-data-structures/03-set.md | 1 + .../05-data-structures/04-dictionary.md | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/curriculum/05-data-structures/03-set.md b/curriculum/05-data-structures/03-set.md index 1fbf56b..1d575c2 100644 --- a/curriculum/05-data-structures/03-set.md +++ b/curriculum/05-data-structures/03-set.md @@ -88,6 +88,7 @@ In this assigment our task is simple one. We need to track distinct *unsold* ite 2. Define a set for all **sold items** (`item[0]` of element in `order` list) and define a set of **all inventory items** (`item[0]` of element in `inventory` list) - you can use set coprehension to do this in one line or use a for loop to iterate over each item in the lists. 3. Create a variable `unsold_items` and set its value to be `sold_items` substracted from `all_inventory_items` 4. Print out items that did not have a sale today. +5. Confirm the program works, commit and push to Github ## What's Next {#next-lesson} Now that we covered index based data structures, it's time to meet **dictionary** which is unique in its *key-value* approach and is probably most used data structure (besides *lists*). \ No newline at end of file diff --git a/curriculum/05-data-structures/04-dictionary.md b/curriculum/05-data-structures/04-dictionary.md index 7b6378b..9b6c7fa 100644 --- a/curriculum/05-data-structures/04-dictionary.md +++ b/curriculum/05-data-structures/04-dictionary.md @@ -124,12 +124,23 @@ for key, value in mydict.items(): print(key, value) ``` - +## Exercise +Complete [[TODO] Exercise 08 — WorkingTitle](#) to practice dictionaries. ## Assignment {#assignment} - +In this assignment, we will completely eliminate list index tracking by refactoring our inventory into a dictionary, mapping each product name directly to its price and stock. + +1. Open `main.py` in our project directory. +2. Replace `inventory` list with an empty dictionary `{}`. +3. When reading users input, assign the item directly to dictionary `inventory`. + ```python + inventory[name] = {"price": price, "stock": stock} + ``` +4. In customer order, look up if item is in the inventory directly with `if item_name in inventory`, verify stock availability with `inventory[item_name]["stock"]` and update stock count in place with `inventory[item_name]["stock"] -= 1` and if stock reaches `0` then delete the item from the inventory using `del inventory[item_name]`. +5. Keep `order` as a list of tuples, and update the `unsold_items` variable to check between keys of the dictionary and tuple elements - use `inventory.keys()` to get a *tuple-like* object of dictionary keys that you can use in this case to substract `order` elements from keys of dictionary. +6. Test your application, make sure it works, commit and push to Github. ## Deepen Your Knowlege {#learn-more} - -## What's Next {#next-lesson} \ No newline at end of file +## What's Next {#next-lesson} +We are now done with basic data structures in Python, next we move on to something even more fun and useful; **functions**. \ No newline at end of file From f8b636df267d42dfe725337d87d431bff1320147 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sat, 12 Sep 2026 09:33:50 +0200 Subject: [PATCH 09/81] Updated lists lessons and ROADMAPmd --- ROADMAP.md | 92 ++++++++++++++++-------- curriculum/05-data-structures/01-list.md | 2 +- 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index f6afe74..6c63ef3 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -3,35 +3,65 @@ This may be subject to change. 1. Introduction * [x] How course works? - * [x] CS Basics - * [x] What is a programming language? - -2. Foundations - * [x] What is Python? - * [ ] Local Development Enviroment (WIP) - * Command Prompt - * Downloading & Installing Python - * VS Code - * `git` and **Github** - * REPL vs *script files* - * [x] Foundations (web based) - * print() - * Variables - * Data types - * Math - * Comparisons - * [ ] Conditionals & Loops (web based) - * If/elif/else - * match/case - * for and while loops - * enumerate() - * zip() - * break / continue - * for-else pattern + * [ ] Motivation and Mindset + * [ ] Asking for Help + * [x] Join the Community + * [x] Computer Science basics, Programming and Python +2. Prerequisites + * [x] Software Installation + * [x] Text and Code Editors + * [x] Command Line Basics + * [x] Python - REPL vs Scripts +3. Git Basics + * [x] Introduction to Git + * [x] Setting up Git and Github + * [x] Git Basics +4. Foundations + * [x] Output, Variables, Core Datatypes + * [x] Arithmetic and String Operations, Comparisons + * [x] User Input and Conditionals + * [x] Loops +5. Data Structures + * [x] Lists + * [x] Tuples + * [x] Sets + * [x] Dictionaries +6. Comprehensions + * [ ] List Coprehension + * [ ] Set Coprehension + * [ ] Dict Coprehension +7. Code Organization * [ ] Functions - * Functions - * `*args`/`**kwargs` - * Mutable argument trap - * LGBT scope rules - * [ ] Mini - Project 1 - * Terminal guessing game? \ No newline at end of file + * [ ] Scope and Namespaces (LEGB rule) + * [ ] Understanding Errors and Error Handling + * [ ] File Handling + * [ ] Modules +8. Capstone Project 1 + * [ ] Problem Solving + * [ ] Problem Solving - Fizz-Buzz Example + * [ ] Capstone Project +9. Built-in and Modules + * [ ] `math` module + * [ ] `json` module + * [ ] `random` module + * [ ] `datetime` module + * [ ] `pathlib` / `os` module + * [ ] `csv` module + * [ ] `sys` module +10. Third-party Modules + * [ ] Virtual Environments + * [ ] Using `pip` and `requirements.txt` + * [ ] Creating python package - `pyproject.toml` file +11. Capstone Project 2 + * [ ] Clean Code Priciples + * [ ] Capstone Project +12. Object Oriented Programming - Part 1 + * [ ] Introduction to classes and instances + * [ ] Methods (instance, class, static) + * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) +13. Capstone Project 3 + * [ ] Capstone Project +14. Object Oriented Programming - Part 2 + * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) +15. Capstone Project 4 + * [ ] Capstone Project diff --git a/curriculum/05-data-structures/01-list.md b/curriculum/05-data-structures/01-list.md index 013a0d0..1903710 100644 --- a/curriculum/05-data-structures/01-list.md +++ b/curriculum/05-data-structures/01-list.md @@ -155,7 +155,7 @@ Learn more about Python Lists from these resources: ::: ## Exercise -Complete [[TODO] Exercise 05 — The Cozy Bakery Inventory](#) to practice list creation, indexing, modification, and using python documentation to solve list tasks. +Complete [[TODO] Exercise 05 — WorkingTitle](#) to practice list creation, indexing, modification, and using python documentation to solve list tasks. ## Assignment {#assignment} 1. Open `main.py` file in our `simple-python-shop` directory From c8504ae5c974bb81f4a151e6b32b6a6b398272e7 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sat, 12 Sep 2026 19:47:55 +0200 Subject: [PATCH 10/81] Added basics of coprehensions lesson --- .../05-data-structures/05-comprehensions.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 curriculum/05-data-structures/05-comprehensions.md diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md new file mode 100644 index 0000000..96036b0 --- /dev/null +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -0,0 +1,54 @@ +--- +id: comprehensions +title: Comprehensions +sidebar_label: Comprehensions +sidebar_position: 5 +lesson: true +isDraft: true +--- +# Comprehensions +Comprehensions in Python provide a short and clear way to create new sequences from existing iterables. Basicly they are a *fancy* syntax for simple **for-loop** pattern. + +## Lesson Overview {#overview} +At the end of the lesson you will know: +* What are comprehensions in Python +* How to write `list`, `dict` or `set` coprehension +* How to use conditions in coprehensions + +The key to understanding list comprehensions is that they’re just `for-loops` over a collection expressed in a more terse and compact syntax. + +We will start with **list coprehension** as it is most common. + +## List Coprehension +Let's imagine we have a task of creating a list of **square** numbers from some other list of numbers. For example, let's assume we have a following list of numbers: +```python +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +``` +To create a new list with **square** of all numbers in a list, we need to first get each element in the list and apply a mathematical operation on it. So it would look something like this: +```python interactive +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +squared = [] +for nmb in nmb_list: + squared.append(nmb**2) + +print(squared) +``` +And the result is correct, but in Python, we can do better. Let's convert our `for-loop` to **list coprehension**. +```python interactive +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +squared = [nmb**2 for nmb in nmb_list] +print(squared) +``` +Result is completly the same, but our code is simpler and more concise. + +:::explore +Documentation Hunting +::: + +## Answer These Questions + +## Exercise + +## Assignment {#assignment} + +## What's Next {#next-lesson} \ No newline at end of file From f29e900c56e206d09ebd163dccb955e230f9f7b7 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 13 Sep 2026 13:27:59 +0200 Subject: [PATCH 11/81] Added more content to coprehensions lessons --- .../05-data-structures/05-comprehensions.md | 95 ++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md index 96036b0..fedda8e 100644 --- a/curriculum/05-data-structures/05-comprehensions.md +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -20,6 +20,11 @@ The key to understanding list comprehensions is that they’re just `for-loops` We will start with **list coprehension** as it is most common. ## List Coprehension +Syntax for this looks like: +```python +[item for item in iterable] +``` + Let's imagine we have a task of creating a list of **square** numbers from some other list of numbers. For example, let's assume we have a following list of numbers: ```python nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] @@ -39,7 +44,95 @@ nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] squared = [nmb**2 for nmb in nmb_list] print(squared) ``` -Result is completly the same, but our code is simpler and more concise. +Result is completly the same, but our code is simpler and more concise. In this simple example we may not see the benefit, but let's add a check there, to only collect **even** numbers. + +If we use **for-loop** we may do something like this. +```python +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +squared_even = [] +for nmb in nmb_list: + if nmb % 2 == 0: + squared_even.append(nmb ** 2) + +print(squared_even) +``` +If we use **list comprehension** it would look like this: +```python interactive +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +squared_even = [nmb ** 2 for nmb in nmb_list if nmb % 2 == 0] +print(squared_even) +``` +The result is again, completly the same, but the syntax is shorter and more concise. + +You do not need to worry about understanding **coprehensions** right away, but they become extremly useful the more you write your code. + +Now that we learned what are list coprehensions, let's look at **dictionary coprehensions** which are very similar in syntax but allows us to create dictionaries in a similar manner. + +## Dictionary Coprehension +When creating a new dictionary using dictionary comprehension, you can perform various operations using expressions to determine the data (key and/or value) that will be stored in the new dictionary. + +Syntax for this looks like: +```python +{key: value for (key,value) in iterable} +``` + +To demonstrate this, let's imagine that you are building a currency converter. You would maybe have a dictionary representing prices in USD and need to convert them to EUR. In traditional **for-loop** you would do something like this: +```python interactive +EUR_CONV_RATE = 0.92 +prices_in_usd = {'pen': 4, 'book': 15, 'keyboard': 60} +prices_in_eur = {} +for name, price in prices_in_usd.items(): + prices_in_eur[name] = round(price * EUR_CONV_RATE, 2) +print(prices_in_eur) +``` +To use **dict coprehension** we would rewrite the above code to: +```python interactive +EUR_CONV_RATE = 0.92 +prices_in_usd = {'pen': 4, 'book': 15, 'keyboard': 60} + +prices_in_eur = {key: round(value * EUR_CONV_RATE, 2) for (key, value) in prices_in_usd.items()} + +print(prices_in_eur) +``` +:::tip +`round()` function rounds the numbers decimal point to specified number of places. It takes in `float` and a number of decimal places - an `integer`. +```python interactive +a = 43.24214213213 +b = round(a, 2) +print(b) +``` +::: + +:::info +In the above code we use `EUR_CONV_RATE` to declare **constant**. Constants are just variables, but are not supposed to be changed during running of your program. They are useful for declaring things that would not change during runtime of your program, and its a convention in Python to write them in `ALL_CAPS`. Unlike some other languages, in Python, these are considered just like regular variables and Python will not stop you from changing them during runtime, so you need to consider this when writing your application. + +The golden rule is: +* If the variable will change during your application runtime, its just a variable and should be written as `variable_name`. +* If the variable will **not** change during your application runtime, then you can consider it a **constant** and write them as `VARIABLE_NAME`. + +Remember that this is just a convention and it is not a rule you *must* follow. +::: + +Now that we covered dictionary coprehensions, we can finally meet **set coprehensions**. + +## Set Coprehension +Set comprehension works best when you want a clean transformation and you also want duplicates to disappear without extra effort. The syntax for **set coprehension** is: +```python +{expression for item in iterable} +``` + +For example, let's use our *squared* example from before: +```python interactive +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +squared = {nmb ** 2 for nmb in nmb_list} +print(squared) +``` +We can also use conditionals to get only specific values: +```python interactive +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +squared_even = {nmb ** 2 for nmb in nmb_list if nmb % 2 == 0} +print(squared_even) +``` :::explore Documentation Hunting From 4b331b8355132b8c9d7aae1ae2e74bde98a1cecb Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 13 Sep 2026 13:39:34 +0200 Subject: [PATCH 12/81] Fixed code block to be 'interactive' --- curriculum/05-data-structures/05-comprehensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md index fedda8e..d7af0c9 100644 --- a/curriculum/05-data-structures/05-comprehensions.md +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -47,7 +47,7 @@ print(squared) Result is completly the same, but our code is simpler and more concise. In this simple example we may not see the benefit, but let's add a check there, to only collect **even** numbers. If we use **for-loop** we may do something like this. -```python +```python interactive nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] squared_even = [] for nmb in nmb_list: From 71088b3b658d0ab67d80e2938b5858c462ebd851 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 13 Sep 2026 16:57:49 +0200 Subject: [PATCH 13/81] Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson --- ROADMAP.md | 31 +++++++++---------- .../05-data-structures/04-dictionary.md | 2 +- .../05-data-structures/05-comprehensions.md | 3 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 71e85a1..30134b3 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -28,25 +28,22 @@ This may be subject to change. * [x] User Input and Conditionals * [x] Loops 5. Data Structures - * [x] Lists - * [x] Tuples - * [x] Sets - * [x] Dictionaries -6. Comprehensions - * [ ] List Coprehension - * [ ] Set Coprehension - * [ ] Dict Coprehension -7. Code Organization + * [x] Lists (WIP) + * [x] Tuples (WIP) + * [x] Sets (WIP) + * [x] Dictionaries (WIP) + * [x] Coprehensions (`list`, `dict` `set`) (WIP) +6. Code Organization * [ ] Functions * [ ] Scope and Namespaces (LEGB rule) * [ ] Understanding Errors and Error Handling * [ ] File Handling * [ ] Modules -8. Capstone Project 1 +7. Capstone Project 1 * [ ] Problem Solving * [ ] Problem Solving - Fizz-Buzz Example * [ ] Capstone Project -9. Built-in and Modules +8. Built-in and Modules * [ ] `math` module * [ ] `json` module * [ ] `random` module @@ -54,20 +51,20 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module -10. Third-party Modules +9. Third-party Modules * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file -11. Capstone Project 2 +10. Capstone Project 2 * [ ] Clean Code Priciples * [ ] Capstone Project -12. Object Oriented Programming - Part 1 +11. Object Oriented Programming - Part 1 * [ ] Introduction to classes and instances * [ ] Methods (instance, class, static) * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -13. Capstone Project 3 +12. Capstone Project 3 * [ ] Capstone Project -14. Object Oriented Programming - Part 2 +13. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -15. Capstone Project 4 +14. Capstone Project 4 * [ ] Capstone Project diff --git a/curriculum/05-data-structures/04-dictionary.md b/curriculum/05-data-structures/04-dictionary.md index 9b6c7fa..66c2957 100644 --- a/curriculum/05-data-structures/04-dictionary.md +++ b/curriculum/05-data-structures/04-dictionary.md @@ -143,4 +143,4 @@ In this assignment, we will completely eliminate list index tracking by refactor ## Deepen Your Knowlege {#learn-more} ## What's Next {#next-lesson} -We are now done with basic data structures in Python, next we move on to something even more fun and useful; **functions**. \ No newline at end of file +We are now done with basic data structures in Python, next we move on to something even more fun and useful, kind of a super power in Python: **coprehensions** \ No newline at end of file diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md index d7af0c9..b625caf 100644 --- a/curriculum/05-data-structures/05-comprehensions.md +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -144,4 +144,5 @@ Documentation Hunting ## Assignment {#assignment} -## What's Next {#next-lesson} \ No newline at end of file +## What's Next {#next-lesson} +Coprehensions are very useful in every day life as a Python programmer, but there is one thing that is universal accross all languages, so let's start a new chapter; *code organization*. First thing to learn are **functions** which enable us to write modular code. \ No newline at end of file From 8dea13e2dfd0fe75cd152afa95f92756337a6e9f Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:47:23 +0200 Subject: [PATCH 14/81] Fixed typos --- .../05-data-structures/05-comprehensions.md | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md index b625caf..0aad0ca 100644 --- a/curriculum/05-data-structures/05-comprehensions.md +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -7,19 +7,19 @@ lesson: true isDraft: true --- # Comprehensions -Comprehensions in Python provide a short and clear way to create new sequences from existing iterables. Basicly they are a *fancy* syntax for simple **for-loop** pattern. +Comprehensions in Python provide a short and clear way to create new sequences from existing iterable. Basically they are a *fancy* syntax for simple **for-loop** pattern. ## Lesson Overview {#overview} At the end of the lesson you will know: * What are comprehensions in Python -* How to write `list`, `dict` or `set` coprehension -* How to use conditions in coprehensions +* How to write `list`, `dict` or `set` comprehension +* How to use conditions in comprehensions The key to understanding list comprehensions is that they’re just `for-loops` over a collection expressed in a more terse and compact syntax. -We will start with **list coprehension** as it is most common. +We will start with **list comprehension** as it is most common. -## List Coprehension +## List Comprehension Syntax for this looks like: ```python [item for item in iterable] @@ -38,13 +38,13 @@ for nmb in nmb_list: print(squared) ``` -And the result is correct, but in Python, we can do better. Let's convert our `for-loop` to **list coprehension**. +And the result is correct, but in Python, we can do better. Let's convert our `for-loop` to **list comprehension**. ```python interactive nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] squared = [nmb**2 for nmb in nmb_list] print(squared) ``` -Result is completly the same, but our code is simpler and more concise. In this simple example we may not see the benefit, but let's add a check there, to only collect **even** numbers. +Result is completely the same, but our code is simpler and more concise. In this simple example we may not see the benefit, but let's add a check there, to only collect **even** numbers. If we use **for-loop** we may do something like this. ```python interactive @@ -62,13 +62,13 @@ nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] squared_even = [nmb ** 2 for nmb in nmb_list if nmb % 2 == 0] print(squared_even) ``` -The result is again, completly the same, but the syntax is shorter and more concise. +The result is again, completely the same, but the syntax is shorter and more concise. -You do not need to worry about understanding **coprehensions** right away, but they become extremly useful the more you write your code. +You do not need to worry about understanding **comprehensions** right away, but they become extremely useful the more you write your code. -Now that we learned what are list coprehensions, let's look at **dictionary coprehensions** which are very similar in syntax but allows us to create dictionaries in a similar manner. +Now that we learned what are list comprehensions, let's look at **dictionary comprehensions** which are very similar in syntax but allows us to create dictionaries similarly. -## Dictionary Coprehension +## Dictionary Comprehension When creating a new dictionary using dictionary comprehension, you can perform various operations using expressions to determine the data (key and/or value) that will be stored in the new dictionary. Syntax for this looks like: @@ -85,7 +85,7 @@ for name, price in prices_in_usd.items(): prices_in_eur[name] = round(price * EUR_CONV_RATE, 2) print(prices_in_eur) ``` -To use **dict coprehension** we would rewrite the above code to: +To use **dict comprehension** we would rewrite the above code to: ```python interactive EUR_CONV_RATE = 0.92 prices_in_usd = {'pen': 4, 'book': 15, 'keyboard': 60} @@ -104,7 +104,7 @@ print(b) ::: :::info -In the above code we use `EUR_CONV_RATE` to declare **constant**. Constants are just variables, but are not supposed to be changed during running of your program. They are useful for declaring things that would not change during runtime of your program, and its a convention in Python to write them in `ALL_CAPS`. Unlike some other languages, in Python, these are considered just like regular variables and Python will not stop you from changing them during runtime, so you need to consider this when writing your application. +In the above code we use `EUR_CONV_RATE` to declare **constant**. Constants are just variables, but are not supposed to be changed during running of your program. They are useful for declaring things that would not change during runtime of your program, and it's a convention in Python to write them in `ALL_CAPS`. Unlike some other languages, in Python, these are considered just like regular variables and Python will not stop you from changing them during runtime, so you need to consider this when writing your application. The golden rule is: * If the variable will change during your application runtime, its just a variable and should be written as `variable_name`. @@ -113,10 +113,10 @@ The golden rule is: Remember that this is just a convention and it is not a rule you *must* follow. ::: -Now that we covered dictionary coprehensions, we can finally meet **set coprehensions**. +Now that we covered dictionary comprehensions, we can finally meet **set comprehensions**. -## Set Coprehension -Set comprehension works best when you want a clean transformation and you also want duplicates to disappear without extra effort. The syntax for **set coprehension** is: +## Set Comprehension +Set comprehension works best when you want a clean transformation, and you also want duplicates to disappear without extra effort. The syntax for **set comprehension** is: ```python {expression for item in iterable} ``` @@ -138,6 +138,14 @@ print(squared_even) Documentation Hunting ::: +:::tip +Comprehensions are very useful and can make your code smaller and easier to understand and reason about. But it also can make your code very difficult to read and understand. + +Use them with caution and remember: +* USE comprehensions while the code is readable +* DO NOT use comprehensions when the code starts to become unreadable and go back to **for-loop** for clarity. +::: + ## Answer These Questions ## Exercise @@ -145,4 +153,4 @@ Documentation Hunting ## Assignment {#assignment} ## What's Next {#next-lesson} -Coprehensions are very useful in every day life as a Python programmer, but there is one thing that is universal accross all languages, so let's start a new chapter; *code organization*. First thing to learn are **functions** which enable us to write modular code. \ No newline at end of file +Comprehensions are very useful in everyday life as a Python programmer, but there is one thing that is universal across all languages, so let's start a new chapter; *code organization*. First thing to learn are **functions** which enable us to write modular code. From dd7c003485e34f5cf0b28c42eb9f6432496cc7fb Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 16 Sep 2026 16:21:03 +0200 Subject: [PATCH 15/81] Couple of changes to lesson and better ROADMAP.md --- ROADMAP.md | 12 ++++++------ curriculum/05-data-structures/05-comprehensions.md | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 30134b3..4ce7139 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -10,7 +10,7 @@ This may be subject to change. 1. Introduction * [x] How course works? * [ ] Motivation and Mindset - * [ ] Asking for Help + * [ ] Asking for Help (WIP) * [x] Join the Community * [x] Computer Science basics, Programming and Python 2. Prerequisites @@ -28,11 +28,11 @@ This may be subject to change. * [x] User Input and Conditionals * [x] Loops 5. Data Structures - * [x] Lists (WIP) - * [x] Tuples (WIP) - * [x] Sets (WIP) - * [x] Dictionaries (WIP) - * [x] Coprehensions (`list`, `dict` `set`) (WIP) + * [ ] Lists (WIP) + * [ ] Tuples (WIP) + * [ ] Sets (WIP) + * [ ] Dictionaries (WIP) + * [ ] Coprehensions (`list`, `dict` `set`) (WIP) 6. Code Organization * [ ] Functions * [ ] Scope and Namespaces (LEGB rule) diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md index 0aad0ca..abea678 100644 --- a/curriculum/05-data-structures/05-comprehensions.md +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -39,7 +39,7 @@ for nmb in nmb_list: print(squared) ``` And the result is correct, but in Python, we can do better. Let's convert our `for-loop` to **list comprehension**. -```python interactive +```python interactive debug nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] squared = [nmb**2 for nmb in nmb_list] print(squared) @@ -57,7 +57,7 @@ for nmb in nmb_list: print(squared_even) ``` If we use **list comprehension** it would look like this: -```python interactive +```python interactive debug nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] squared_even = [nmb ** 2 for nmb in nmb_list if nmb % 2 == 0] print(squared_even) @@ -86,7 +86,7 @@ for name, price in prices_in_usd.items(): print(prices_in_eur) ``` To use **dict comprehension** we would rewrite the above code to: -```python interactive +```python interactive debug EUR_CONV_RATE = 0.92 prices_in_usd = {'pen': 4, 'book': 15, 'keyboard': 60} @@ -128,7 +128,7 @@ squared = {nmb ** 2 for nmb in nmb_list} print(squared) ``` We can also use conditionals to get only specific values: -```python interactive +```python interactive debug nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] squared_even = {nmb ** 2 for nmb in nmb_list if nmb % 2 == 0} print(squared_even) From 6a7903ff87c46bd8382ffb3e953f4237c6404161 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 16 Sep 2026 18:37:23 +0200 Subject: [PATCH 16/81] Fixed "Learn More" sections and made them all similar style --- curriculum/05-data-structures/01-list.md | 1 - curriculum/05-data-structures/02-tuple.md | 4 +-- curriculum/05-data-structures/03-set.md | 7 ++-- .../05-data-structures/04-dictionary.md | 9 +++-- .../05-data-structures/05-comprehensions.md | 33 +++++++++++++++---- 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/curriculum/05-data-structures/01-list.md b/curriculum/05-data-structures/01-list.md index 926cedf..4adb8f6 100644 --- a/curriculum/05-data-structures/01-list.md +++ b/curriculum/05-data-structures/01-list.md @@ -7,7 +7,6 @@ lesson: true isDraft: true --- # List -## Introduction {#introduction} Up until now we have stored a single value in a variable, but what if we need to hold multiple values in some variable? Do we create multiple variables? Of course not, Python has a *built-in* mechanisms for dealing with collections of data which we call **data structures**. In this lesson we first take a look at **list**. Lists in Python are *built-in* data structure for storing ordered collections of items. They are **ordered** meaning they keep the order in which data came in. They are also **mutable** which means we can change them in place without creating a new copy. They can hold any other type of data including other lists or other data structures. Lists are probably the most used data structure in Python. diff --git a/curriculum/05-data-structures/02-tuple.md b/curriculum/05-data-structures/02-tuple.md index 9ff40f0..8be316b 100644 --- a/curriculum/05-data-structures/02-tuple.md +++ b/curriculum/05-data-structures/02-tuple.md @@ -51,9 +51,7 @@ Unlike lists, as we cannot modify tuples, we don't have a lot of methods availab ``` :::explore[Learn more about Python Tuples] -Read these resources to learn more about tuples in Python: -* [Python built-in types: tuples from RealPython](https://realpython.com/ref/builtin-types/tuple/) -* [Tuples and Sequences from official Python documentation](https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences) +Deep dive into Python tuples in this [Deep Dive: tuples](https://realpython.com/python-tuple/) article by **Real Python** which takes you deep in topic of tuples and their usecases. ::: ## Exercise diff --git a/curriculum/05-data-structures/03-set.md b/curriculum/05-data-structures/03-set.md index 2b259ef..9253acd 100644 --- a/curriculum/05-data-structures/03-set.md +++ b/curriculum/05-data-structures/03-set.md @@ -7,7 +7,6 @@ lesson: true isDraft: true --- # Set -## Introduction {#introduction} A **set** in Python is unordered collection of unique elements. **Unordered** means it does not keep the order of the elements and **unique** means it does not allow duplicates. Its mostly used when removing duplicates from list or performing quick membership tests (checking to see if some element belongs to both sets). @@ -73,9 +72,9 @@ print("Difference:", set1 - set2) ``` :::explore[Learn more about Python Sets] -Learn more about sets in these materials: -* [Python built-in data types from RealPython](https://realpython.com/ref/builtin-types/set/) -* [Python data structures: set from official Python documentation](https://docs.python.org/3/tutorial/datastructures.html#sets) +Explore Python sets deeper by visiting this [built-in: set] article from **Real Python** (especially the part about additional methods which come in handy when working with sets). + +Remember you do not need to remember all the methods there are. Just read through them, to know they exist. ::: ## Exercise diff --git a/curriculum/05-data-structures/04-dictionary.md b/curriculum/05-data-structures/04-dictionary.md index c946b27..34516ac 100644 --- a/curriculum/05-data-structures/04-dictionary.md +++ b/curriculum/05-data-structures/04-dictionary.md @@ -7,7 +7,6 @@ lesson: true isDraft: true --- # Dictionary -## Introduction {#introduction} Dictionaries in Python are mutable and unordered collection data structure. **Mutable** meaning it can be modified after creating and **unordered** meaning it does not keep track of it's elements. Dictionaries are something special, usually called **key-value** data structure because of the way you store data inside them. You will certanly do a lot of work involving dictionaries in your python applications and its a very powerful concept, so let's get started. @@ -124,6 +123,12 @@ for key, value in mydict.items(): print(key, value) ``` +:::explore[Learn more about Python dicts] +Read this [built-in: dict](https://realpython.com/ref/builtin-types/dict/) article from **Real Python** and pay special attention to sections **dict Operators** and **dict Methods**. + +Remember, just read through, you do not have to know it all. +::: + ## Exercise Complete [[TODO] Exercise 08 — WorkingTitle](#) to practice dictionaries. @@ -140,7 +145,5 @@ In this assignment, we will completely eliminate list index tracking by refactor 5. Keep `order` as a list of tuples, and update the `unsold_items` variable to check between keys of the dictionary and tuple elements - use `inventory.keys()` to get a *tuple-like* object of dictionary keys that you can use in this case to substract `order` elements from keys of dictionary. 6. Test your application, make sure it works, commit and push to Github. -## Deepen Your Knowlege {#learn-more} - ## What's Next {#next-lesson} We are now done with basic data structures in Python, next we move on to something even more fun and useful, kind of a super power in Python: **coprehensions** \ No newline at end of file diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md index abea678..e6e0b86 100644 --- a/curriculum/05-data-structures/05-comprehensions.md +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -64,6 +64,31 @@ print(squared_even) ``` The result is again, completely the same, but the syntax is shorter and more concise. +Let's look at the final type of list comprehension, which will produce one value if the condition is `True` or something else if the condition is `False`. For example, let's say we need to produce a list, containing `True` if the number is even or `False` if its odd. + +In classic python **for-loop** style, we would do something like this: +```python interactive +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +even_mask = [] +for nmb in nmb_list: + if nmb % 2 == 0: + even_mask.append(True) + else: + even_mask.append(False) +print(even_mask) +``` + +But Python let's us use its super power here also: +```python interactive debug +nmb_list = [1, 2, 3, 4, 5, 6, 7, 8] +even_mask = [True for nmb in nmb_list if nmb % 2 == 0 else False] +print(even_mask) +``` + +:::tip[Superpowers work with any comprehension] +`if condition` and `if condition else` works will all comprehensions and not just with lists, and they work in the same manner. +::: + You do not need to worry about understanding **comprehensions** right away, but they become extremely useful the more you write your code. Now that we learned what are list comprehensions, let's look at **dictionary comprehensions** which are very similar in syntax but allows us to create dictionaries similarly. @@ -134,11 +159,7 @@ squared_even = {nmb ** 2 for nmb in nmb_list if nmb % 2 == 0} print(squared_even) ``` -:::explore -Documentation Hunting -::: - -:::tip +:::warning Comprehensions are very useful and can make your code smaller and easier to understand and reason about. But it also can make your code very difficult to read and understand. Use them with caution and remember: @@ -146,8 +167,6 @@ Use them with caution and remember: * DO NOT use comprehensions when the code starts to become unreadable and go back to **for-loop** for clarity. ::: -## Answer These Questions - ## Exercise ## Assignment {#assignment} From dc1a1863a93dff1c96ec4119c7937a577c3b8df4 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 16 Sep 2026 22:56:24 +0200 Subject: [PATCH 17/81] Updated roadmap with missing topics --- ROADMAP.md | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 4ce7139..6d2a4df 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -36,14 +36,31 @@ This may be subject to change. 6. Code Organization * [ ] Functions * [ ] Scope and Namespaces (LEGB rule) - * [ ] Understanding Errors and Error Handling - * [ ] File Handling + * [ ] Type Hints * [ ] Modules 7. Capstone Project 1 * [ ] Problem Solving * [ ] Problem Solving - Fizz-Buzz Example + * [ ] Capstone Project - **Hangman game** +8. Errors, Debugging, I/O + * [ ] Understanding Errors and Error Handling + * [ ] `logging` module + * [ ] Debugging tehniques + * [ ] File Handling +9. Capstone Project 2 + * [ ] Git Workflow: Branches and Pull Requests + * [ ] Revisiting Project 1 (hangman game): + * Creating branch, adding features, merging back to `main` + * Loading *words* from external file + * Catching and logging errors * [ ] Capstone Project -8. Built-in and Modules +10. Intermediate Python + * [ ] Decorators + * [ ] Generators + * [ ] Context Managers +11. Capstone Project 3 + * [ ] Capstone Project +12. Built-in and Modules * [ ] `math` module * [ ] `json` module * [ ] `random` module @@ -51,20 +68,25 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module -9. Third-party Modules + * [ ] `re` module +13. Third-party Modules * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file -10. Capstone Project 2 + * [ ] ? Linting, Formatting, Type Checking (`ruff`, `mypy`) ? +14. Capstone Project 4 * [ ] Clean Code Priciples * [ ] Capstone Project -11. Object Oriented Programming - Part 1 + * [ ] Testing Your Code (`pytest`) + * [ ] Revisit Project 4 + * Develop a testing suite for the project +15. Object Oriented Programming - Part 1 * [ ] Introduction to classes and instances * [ ] Methods (instance, class, static) * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -12. Capstone Project 3 +16. Capstone Project 5 * [ ] Capstone Project -13. Object Oriented Programming - Part 2 +17. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -14. Capstone Project 4 +18. Capstone Project 6 * [ ] Capstone Project From b59c0eb19a0560139c98edd198823d9a5a9a0f98 Mon Sep 17 00:00:00 2001 From: amotech Date: Sat, 26 Sep 2026 20:06:54 +0000 Subject: [PATCH 18/81] first comm.. for ask4help --- .../01-introduction/03-asking-for-help.md | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index 51b555c..81d05fd 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -6,5 +6,40 @@ sidebar_position: 3 lesson: true isDraft: true --- + # Asking For Help -## Work in progress \ No newline at end of file +**Introduction**: Getting stuck in your coding or even a learning is really part of the journey, and that is the number one why this lesson (ask for help) exists. + +## Goal +In this lesson you will learn how to get help whenever you need it. And by the end of this lesson you should be familiar with getting stcuk and how to seek for help. + + +## Lesson outline +* How to Get Help +* + +## How to Get Help +### 1. Before You Ask +Check if: +- your indentations are correct or valid +- your syntax are correct or valid +- your code is complete as you intended + +**If** any of above is Fasle, Fix them and re-run your code. + +**Else**, if all of above is True and error still persist, proceed to the step 2(the question space) of this topic. + + +### 2. The Question space +Paste your code below: + +′′′python + +′′′ + +### 3. How to Format Your Code +... + +### 4. What to Expect Next +Once you have submitted your help request, sit down tight and the appropriate help will be sent straight to you. + From 34f582cd1b4031e5f1d480b9871d480f7cb45d6f Mon Sep 17 00:00:00 2001 From: amotech Date: Sun, 27 Sep 2026 14:04:15 +0000 Subject: [PATCH 19/81] First on repo corr... --- curriculum/01-introduction/03-asking-for-help.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index 81d05fd..faba68f 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -25,7 +25,7 @@ Check if: - your syntax are correct or valid - your code is complete as you intended -**If** any of above is Fasle, Fix them and re-run your code. +**If** any of above is False, Fix them and re-run your code. **Else**, if all of above is True and error still persist, proceed to the step 2(the question space) of this topic. From 030175a3bae15ee72e0c53c0e1c577e3a80f6d8e Mon Sep 17 00:00:00 2001 From: amotech Date: Mon, 28 Sep 2026 15:41:50 +0000 Subject: [PATCH 20/81] test3 --- ROADMAP.md | 76 +++++++++++++++++++ .../01-introduction/03-asking-for-help.md | 4 + 2 files changed, 80 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index 6d2a4df..1b28d2f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -61,6 +61,66 @@ This may be subject to change. 11. Capstone Project 3 * [ ] Capstone Project 12. Built-in and Modules + * [-] Data Structures + * [-] List + * [-] Tuple + * [-] Set + * [-] Dictionary + * [ ] Functions + * [ ] Project 1 +5. Modules, Working with Files and Error Handling + * [ ] Working with multiple files (`__init.py__`, directory structure, etc...) + * [ ] Opening, Closing and Manipulating files + * [ ] Error Handling (`try-except-else-finally`) + * [ ] Custom Exceptions + * [ ] Defensive Coding patterns + * [ ] Working with structured data (`json`, `csv`, etc...) + * [ ] Project 2 +6. OOP, Virtual Environments and third party libraries, Working with APIs + * [ ] Classes and OOP + * [ ] Usage and setup of virtual environments + * [ ] Installation of third party libraries + * [ ] Working with APIs + * [ ] Project 3 - *probably: * weather app +7. Working on Projects, Solving bugs, Reading errors + * [ ] Motivation and Mindset + * [ ] Asking for Help + * [x] Join the Community + * [x] Computer Science basics, Programming and Python +2. Prerequisites + * [x] Software Installation + * [x] Text and Code Editors + * [x] Command Line Basics + * [x] Python - REPL vs Scripts +3. Git Basics + * [x] Introduction to Git + * [x] Setting up Git and Github + * [x] Git Basics +4. Foundations + * [x] Output, Variables, Core Datatypes + * [x] Arithmetic and String Operations, Comparisons + * [x] User Input and Conditionals + * [x] Loops +5. Data Structures + * [x] Lists + * [x] Tuples + * [x] Sets + * [x] Dictionaries +6. Comprehensions + * [ ] List Coprehension + * [ ] Set Coprehension + * [ ] Dict Coprehension +7. Code Organization + * [ ] Functions + * [ ] Scope and Namespaces (LEGB rule) + * [ ] Understanding Errors and Error Handling + * [ ] File Handling + * [ ] Modules +8. Capstone Project 1 + * [ ] Problem Solving + * [ ] Problem Solving - Fizz-Buzz Example + * [ ] Capstone Project +9. Built-in and Modules * [ ] `math` module * [ ] `json` module * [ ] `random` module @@ -89,4 +149,20 @@ This may be subject to change. 17. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) 18. Capstone Project 6 +10. Third-party Modules + * [ ] Virtual Environments + * [ ] Using `pip` and `requirements.txt` + * [ ] Creating python package - `pyproject.toml` file +11. Capstone Project 2 + * [ ] Clean Code Priciples + * [ ] Capstone Project +12. Object Oriented Programming - Part 1 + * [ ] Introduction to classes and instances + * [ ] Methods (instance, class, static) + * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) +13. Capstone Project 3 + * [ ] Capstone Project +14. Object Oriented Programming - Part 2 + * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) +15. Capstone Project 4 * [ ] Capstone Project diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index faba68f..b5e2a76 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -43,3 +43,7 @@ Paste your code below: ### 4. What to Expect Next Once you have submitted your help request, sit down tight and the appropriate help will be sent straight to you. +## Introduction +This lesson is intended to help you become good in seeking for help + +## Work in progress From 2e9e7cf039a27bb0b6ea276769748f5c48c229e2 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 16 Sep 2026 16:21:03 +0200 Subject: [PATCH 21/81] Couple of changes to lesson and better ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 1b28d2f..7d681ff 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -84,7 +84,7 @@ This may be subject to change. * [ ] Project 3 - *probably: * weather app 7. Working on Projects, Solving bugs, Reading errors * [ ] Motivation and Mindset - * [ ] Asking for Help + * [ ] Asking for Help (WIP) * [x] Join the Community * [x] Computer Science basics, Programming and Python 2. Prerequisites From e4497d058553816ef66083137ce61ad33a184e12 Mon Sep 17 00:00:00 2001 From: amotech Date: Thu, 1 Oct 2026 14:36:46 +0000 Subject: [PATCH 22/81] ask4help update v0.1 --- .git-bestPractices | 5 ++ .vscode/extensions.json | 5 ++ .../01-introduction/03-asking-for-help.md | 75 +++++++++++++++---- 3 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 .git-bestPractices create mode 100644 .vscode/extensions.json diff --git a/.git-bestPractices b/.git-bestPractices new file mode 100644 index 0000000..95bafbc --- /dev/null +++ b/.git-bestPractices @@ -0,0 +1,5 @@ +#after every update and before any commit/push, run: +- git fetch upstream +- git rebase upstream/main +- git push origin master + diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..0bbab56 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "bowlerr.offline-markdown-preview" + ] +} \ No newline at end of file diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index b5e2a76..363c961 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -7,20 +7,27 @@ lesson: true isDraft: true --- -# Asking For Help -**Introduction**: Getting stuck in your coding or even a learning is really part of the journey, and that is the number one why this lesson (ask for help) exists. +# Asking For Help ❔ +**INTRODUCTION**: Getting stuck in your coding or even a learning is really part of the journey, and that is the number one why this lesson (ask for help) exists. -## Goal -In this lesson you will learn how to get help whenever you need it. And by the end of this lesson you should be familiar with getting stcuk and how to seek for help. +## The Goal 🥅⚽ +In this lesson you will learn how to get help whenever you need it. And by the end of this lesson you should be familiar with getting stuck and how to seek for help. -## Lesson outline +## Lesson outline 📝 * How to Get Help -* +* Who to Ask for Help +* Where to Ask for Help -## How to Get Help -### 1. Before You Ask -Check if: +## How to Get Help ❔ +Steps to follow to get help: +* Before you ask, do some checks +* Use the question space +* format your code properly +* Know what to expect next + +### 1. Before You Ask ⤴➡ +Before you ask anything check if: - your indentations are correct or valid - your syntax are correct or valid - your code is complete as you intended @@ -30,20 +37,58 @@ Check if: **Else**, if all of above is True and error still persist, proceed to the step 2(the question space) of this topic. -### 2. The Question space +### 2. The Question space 📰❔ Paste your code below: ′′′python +import A + ′′′ -### 3. How to Format Your Code +### 3. How to Format Your Code 🔃 +- You are required to format your code (_python code_) using the markdown language in order to get the appropriate responses to your help requests. ... -### 4. What to Expect Next +### 4. What to Expect Next ➡ Once you have submitted your help request, sit down tight and the appropriate help will be sent straight to you. -## Introduction -This lesson is intended to help you become good in seeking for help +If unfortunately the help response delays or never comes, use the next approach which is _WHO TO ASK_. + + +## Who to Ask for Help 🧔🏻❔ +subs: +* Ask yourself +* Ask someone with experience +* Ask a trusted community +* Ask an Ai agent + +### 1. Ask Yourself Before Anyone +You may say, why myself, i don't know?—Ofcourse you know all the answers to your own questions most of the times. **Ask yourself why, why did the error come; Ask yourself how, how did the error come; and Ask yourself what, what brought up a particular error** :(. You are not actually finding the correct solution to the cause of the error with these questions overnight (as if it was a magic :)), *but* what you are doing is you are training your thinking which may help you think creatively gradually—to solve future problems. "Problem solving requires a creative and effective thinking"—Baldwin.J,. college success(2021). + +After you have had your answers to those three question, store them safely as we will learn how they might become useful later in this lesson. + +### 2. Ask Someone with Experience +Why ask someone with experience?—An experienced programmer, specifically python programmer, knows how to solve or debug almost every bug or error respectively. Therefore asking an experienced person means there is a higher probability you will get a solution to an/a error/bug. + +Now let see how your answers at the _ask yourself_ sub gets useful here. Compare your answers obtained at the _ask yourself_ sub to the ones you obtained from the experienced programmer and **Ask youself one more time—what did i missed?**—Keep this particular answer to yourself (treat it as important), it might help you in your future decisions when debugging other or similar errors later on. + +### 3. Ask a Trusted Community +Though there isn't a full guarantee that a community will contain only experienced programmers,—That is there would be beginners, intermediates and experts—but there are people with at least an experience if not much, these people might have already at least solved a bug which you just met, and could share with you how they handled it—which might be a fantastic approach you could learn also. + +Therefore asking verified communities like the stackoverflow, github, telegram groups, reddit, discord and others i could'nt mention—though one should proceed this with caution—is a must once you are learning the python or any other programming langauge. + +### 4. Ask an AI Agent +AI tools or agents are a smart way to debug errors faster, but the question is—Does the AI agent know the best approch to avoid future code breaks? + +This does not neccessarily mean using AI assistance for debugging errors is bad. But for best decision sake; That is if you know enough or understand how to select the best approach out of the many provided by the AI model, then you are encouraged to proceed with this approach—the advice is simple, that is use AI to recall the best solutions you already know quickly and not to decide the best solutions for you. + +This really counts in a serious project or even in the real world practices, but it is also a good thing to keep it in practice now—even if you are learning. + + +## Where to Ask for Help +- _work in progress_ + + -## Work in progress +[ **_WORK IN PROGRESS_** ] From 87f7386100dbb0102a97cfde649efaacbdd8b71f Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 18:23:32 +0200 Subject: [PATCH 23/81] Update CONTRIBUTING.md to better instruct contributors --- CONTRIBUTING.md | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d9a3ce3..bdeaeab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,46 @@ Thanks for helping improve this project! Every contribution counts, from fixing a single typo to writing a whole new lesson. +## 🚀 Before You Start + +You do **not** have write access to this repo directly — all changes go through a fork and a Pull Request. If you clone this repo and try to push to it, you'll get a `403` error. That's expected; it just means you're pushing to the wrong place. + +1. **Fork** this repo (the "Fork" button, top-right) — you'll get your own copy at `github.com//Curriculum`. +2. **Clone your fork**, not this repo: + ``` + git clone https://github.com//Curriculum.git + ``` +3. Add this repo as a second remote, called `upstream`, so you can pull in new changes later: + ``` + git remote add upstream https://github.com/ThePythonLedger/Curriculum.git + ``` +4. Make your changes and push to **your fork** (`origin`), then open a PR from your fork's branch into `ThePythonLedger:main`. + +### Keeping your fork in sync + +Content here moves fast — other contributors' lessons get merged into `main` regularly. If your fork falls behind, your PR can end up showing dozens of commits and files that aren't actually yours, just because your branch never caught up. Syncing before you start, and again before you open a PR, avoids that. + +**Before you start new work:** +``` +git checkout main +git fetch upstream +git rebase upstream/main +git push origin main +``` + +**Before opening a PR** (or if you're asked to update an existing one): +``` +git fetch upstream +git rebase upstream/main +git push --force-with-lease origin your-branch-name +``` + +If you hit conflicts during rebase, Git will pause and tell you which files need attention. Fix them, then run `git add ` and `git rebase --continue`. + +> **Why rebase instead of merge?** Merging pulls in a merge commit and tangles your branch's history with everyone else's. Rebasing replays just your commits on top of the latest `main`, so your PR shows only the changes you actually made — easier for us to review, and easier for you to reason about. + +--- + ## Which path is mine? | I want to... | What to do | Issue needed? | @@ -42,7 +82,7 @@ New content needs to be coordinated first, so we don't end up with two people wr 1. **Check the [Curriculum Roadmap](./curriculum-roadmap.md)** to see which lessons still need to be written. 2. **Open an issue** describing the lesson you'd like to write and its scope. 3. **Wait to be assigned.** A maintainer will assign the issue to you. (If nobody replies after a few days, leave a comment on the issue.) -4. **Fork** this repository. +4. **Fork** this repository (see [Before You Start](#-before-you-start) if you haven't already). 5. **Create a new `.md` file** in the appropriate folder (e.g. `01-foundations/`). 6. **Follow the [Lesson Guidelines](./lesson-guidelines.md)** so your lesson fits in with the existing lessons. 7. **Open a draft PR** as soon as you have some content. We'll label the lesson as *Being Worked On*, so others know it's taken. Our pipeline checks your document for inconsistencies automatically, even on draft PRs, so you get early feedback. @@ -85,6 +125,12 @@ If something is missing, the bot will: ## ❓ FAQ +**I cloned the repo and tried to push, but I got a 403.** +You cloned this repo directly instead of forking it. See [Before You Start](#-before-you-start) — fork the repo first, then clone and push to your own fork. + +**My PR shows a lot more commits/files than I actually changed.** +Your fork's branch probably fell behind `main`. Sync it with `git fetch upstream && git rebase upstream/main`, then push with `--force-with-lease`. See [Keeping your fork in sync](#keeping-your-fork-in-sync). + **My PR got the `needs-issue` label. Did I do something wrong?** No! It just means your PR is bigger than a quick fix or has no assigned issue linked. Follow the steps in [Linking your issue](#-linking-your-issue). From 2bfe0cfe3ecbd580d017ccb6f5a065b2d5ecb9c8 Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 22:51:49 +0200 Subject: [PATCH 24/81] Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow. --- .github/workflows/sync_roadmap_status.yml | 47 ++++++ ROADMAP.md | 2 +- bot_challenges/01-inventory-system.md | 20 --- scripts/roadmap/sync_discord.py | 133 +++++++++++++++++ scripts/roadmap/sync_roadmap.py | 169 ++++++++++++++++++++++ 5 files changed, 350 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/sync_roadmap_status.yml delete mode 100644 bot_challenges/01-inventory-system.md create mode 100644 scripts/roadmap/sync_discord.py create mode 100644 scripts/roadmap/sync_roadmap.py diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml new file mode 100644 index 0000000..5194817 --- /dev/null +++ b/.github/workflows/sync_roadmap_status.yml @@ -0,0 +1,47 @@ +name: Sync Roadmap Status + +on: + issues: + types: [assigned, unassigned, closed, reopened] + # pull_request_target (not pull_request) so the workflow gets write + # access even for PRs opened from forks. Safe here because we never + # check out or run the fork's code — we only read the PR body + # (already in the event payload) and write to ROADMAP.md on main. + pull_request_target: + types: [opened, ready_for_review, closed] + +permissions: + contents: write + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Update ROADMAP.md + id: update + run: python scripts/roadmap/sync_roadmap.py + env: + GITHUB_EVENT_NAME: ${{ github.event_name }} + GITHUB_EVENT_PATH: ${{ github.event_path }} + + - name: Commit ROADMAP.md + if: steps.update.outputs.changed == 'true' + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: sync roadmap status [skip ci]" + file_pattern: ROADMAP.md + + - name: Sync Discord + if: steps.update.outputs.changed == 'true' + run: python scripts/roadmap/sync_discord.py + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} \ No newline at end of file diff --git a/ROADMAP.md b/ROADMAP.md index 7d681ff..f03b6d6 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -3,7 +3,7 @@ This may be subject to change. ## Legend `[ ]` - no work has been done -`[-]` - somebody is working on this but it has not yet been completed. There should be a related PR. +`[ ] 🚧` - work in progress (assigned / open PR) `[x]` - lesson completed ## Roadmap diff --git a/bot_challenges/01-inventory-system.md b/bot_challenges/01-inventory-system.md deleted file mode 100644 index 98267c0..0000000 --- a/bot_challenges/01-inventory-system.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: "01-inventory-system" -title: "RPG Inventory System" -web_lesson: "https://pythonledger.com/docs/lists" -total_stages: 2 ---- - -# Stage 1 -Create a list named `inventory` containing 3 strings: `"potion"`, `"sword"`, and `"shield"`. - -- HINT: Make sure item names are wrapped in quotes and separated by commas. -- DONE: Print the entire list using `print(inventory)`. - ----STAGE--- - -# Stage 2 -Print only the **second** item from your `inventory` list. - -- HINT: Python lists are 0-indexed (0 = first item, 1 = second item). -- DONE: Console output displays only the string `"sword"`. \ No newline at end of file diff --git a/scripts/roadmap/sync_discord.py b/scripts/roadmap/sync_discord.py new file mode 100644 index 0000000..57a9f67 --- /dev/null +++ b/scripts/roadmap/sync_discord.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +""" +Renders ROADMAP.md into Discord embeds and PATCHes a set of existing +webhook messages, so a Discord channel mirrors the roadmap's current +state. Uses only the standard library — no extra dependency to install +in the workflow. + +Requires: + DISCORD_WEBHOOK_URL The webhook's execute URL + (https://discord.com/api/webhooks//) + DISCORD_MESSAGE_IDS JSON array of message IDs to update, one per + "page" of phases (see PHASES_PER_MESSAGE below) + +One-time setup: send an initial message through the webhook manually +(any content) for each page you'll need, note the returned message +IDs, and store them as DISCORD_MESSAGE_IDS. This script only edits +those messages — it never creates new ones — so the roadmap always +lives at the same spot in the channel. +""" + +import json +import os +import re +import sys +import urllib.request + +ROADMAP_PATH = "ROADMAP.md" +PHASES_PER_MESSAGE = ( + 9 # 18 phases / 9 = 2 messages; keeps each embed well under Discord's limits +) + +STATE_EMOJI = {" ": "⬜", "-": "🚧", "x": "✅"} +WIP_BADGE = "🚧" + +PHASE_RE = re.compile(r"^\d+\.\s+(.+)$") +ITEM_RE = re.compile( + rf"^\s*\*\s*\[(?P[ x])\]\s*(?P{WIP_BADGE}\s*)?(?P.+?)\s*$" +) + + +def item_state(check: str, badge: str | None) -> str: + if check == "x": + return "x" + return "-" if badge else " " + + +Phase = tuple[str, list[tuple[str, str]]] + + +def parse_roadmap(text: str) -> list[Phase]: + phases: list[Phase] = [] + current_items: list[tuple[str, str]] = [] + current_title: str | None = None + + for raw_line in text.splitlines(): + phase_match = PHASE_RE.match(raw_line) + if phase_match: + if current_title is not None: + phases.append((current_title, current_items)) + current_title = phase_match.group(1) + current_items = [] + continue + + item_match = ITEM_RE.match(raw_line) + if item_match and current_title is not None: + state = item_state(item_match.group("check"), item_match.group("badge")) + current_items.append((state, item_match.group("text"))) + + if current_title is not None: + phases.append((current_title, current_items)) + + return phases + + +def build_embed(phases: list[Phase]) -> dict: + fields = [] + for title, items in phases: + lines = [f"{STATE_EMOJI[state]} {text}" for state, text in items] + value = "\n".join(lines) or "—" + fields.append({"name": title[:256], "value": value[:1024], "inline": False}) + + return { + "title": "📍 Curriculum Roadmap", + "color": 0x3776AB, + "fields": fields[:25], + } + + +def patch_message(webhook_url: str, message_id: str, embed: dict) -> None: + url = f"{webhook_url}/messages/{message_id}" + payload = json.dumps({"embeds": [embed]}).encode("utf-8") + req = urllib.request.Request( + url, + data=payload, + method="PATCH", + headers={"Content-Type": "application/json"}, + ) + with urllib.request.urlopen(req) as resp: + if resp.status not in (200, 204): + print( + f"Unexpected status {resp.status} updating message {message_id}", + file=sys.stderr, + ) + + +def main() -> None: + webhook_url = os.environ["DISCORD_WEBHOOK_URL"] + message_ids = json.loads(os.environ["DISCORD_MESSAGE_IDS"]) + + with open(ROADMAP_PATH, encoding="utf-8") as f: + phases = parse_roadmap(f.read()) + + chunks = [ + phases[i : i + PHASES_PER_MESSAGE] + for i in range(0, len(phases), PHASES_PER_MESSAGE) + ] + + if len(chunks) != len(message_ids): + print( + f"Expected {len(chunks)} message(s) for {len(phases)} phases, " + f"but DISCORD_MESSAGE_IDS has {len(message_ids)}. Update the " + f"variable or PHASES_PER_MESSAGE so they match.", + file=sys.stderr, + ) + sys.exit(1) + + for message_id, chunk in zip(message_ids, chunks): + patch_message(webhook_url, message_id, build_embed(chunk)) + print(f"Updated message {message_id} ({len(chunk)} phases)") + + +if __name__ == "__main__": + main() diff --git a/scripts/roadmap/sync_roadmap.py b/scripts/roadmap/sync_roadmap.py new file mode 100644 index 0000000..45291ba --- /dev/null +++ b/scripts/roadmap/sync_roadmap.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +""" +Reads the GitHub event that triggered this workflow run (an issue or PR +change) and updates the matching line in ROADMAP.md to one of three +states: + + [ ] Lists — #34 not started + [ ] 🚧 Lists — #34 in progress (assigned / open PR) + [x] Lists — #34 done (merged / issue closed) + +GitHub's task-list rendering only recognizes [ ] and [x] as real, +interactive checkboxes — anything else (like a bare [-]) is just +literal text with no checkbox widget. So the checkbox itself stays +strictly boolean (done / not done), and "in progress" is layered on +as a 🚧 badge in the visible text instead of a third bracket state. + +This only touches roadmap lines that already reference an issue, e.g.: + + * [ ] Lists — #34 + +Lines with no "— #N" suffix are left alone — link an issue to a lesson +by adding that suffix, and the automation picks it up from then on. +""" + +import json +import os +import re + +ROADMAP_PATH = "ROADMAP.md" +WIP_BADGE = "🚧" + +# Internal state codes (unchanged from before): " " = not started, +# "-" = in progress, "x" = done. Only how they're RENDERED changes. +STATE_RENDER = { + " ": {"check": " ", "badge": ""}, + "-": {"check": " ", "badge": f"{WIP_BADGE} "}, + "x": {"check": "x", "badge": ""}, +} + +# Matches e.g. " * [ ] 🚧 Lists — #34" and captures the checkbox, +# an optional WIP badge, and the issue number — everything else on +# the line is left untouched. +LINE_RE = re.compile( + r"^(?P\s*\*\s*\[)(?P[ x])(?P\]\s*)" + rf"(?P{WIP_BADGE}\s*)?" + r"(?P.*?—\s*#)(?P\d+)(?P.*)$" +) + + +def current_state(check: str, badge: str | None) -> str: + if check == "x": + return "x" + return "-" if badge else " " + + +# Matches "Closes #12", "Fixes #34", "Resolves #7", etc. (repeatable, case-insensitive) +ISSUE_REF_RE = re.compile( + r"(?:clos(?:e[sd]?)|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)", re.IGNORECASE +) + + +def marker_for_issue_event(event: dict) -> dict[int, str]: + action = event["action"] + issue_number = event["issue"]["number"] + + if action == "assigned": + return {issue_number: "-"} + if action == "unassigned": + return {issue_number: " "} + if action == "closed": + return {issue_number: "x"} + if action == "reopened": + has_assignee = bool(event["issue"].get("assignees")) + return {issue_number: "-" if has_assignee else " "} + return {} + + +def marker_for_pr_event(event: dict) -> dict[int, str]: + action = event["action"] + pr = event["pull_request"] + body = pr.get("body") or "" + issue_numbers = {int(n) for n in ISSUE_REF_RE.findall(body)} + if not issue_numbers: + return {} + + if action in ("opened", "ready_for_review"): + marker = "-" + elif action == "closed": + marker = "x" if pr.get("merged") else "-" + else: + return {} + + return {n: marker for n in issue_numbers} + + +def load_event() -> dict: + with open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8") as f: + return json.load(f) + + +def compute_updates() -> dict[int, str]: + event_name = os.environ["GITHUB_EVENT_NAME"] + event = load_event() + + if event_name == "issues": + return marker_for_issue_event(event) + if event_name == "pull_request" or event_name == "pull_request_target": + return marker_for_pr_event(event) + return {} + + +def apply_updates(updates: dict[int, str]) -> bool: + with open(ROADMAP_PATH, encoding="utf-8") as f: + lines = f.readlines() + + changed = False + for i, line in enumerate(lines): + m = LINE_RE.match(line.rstrip("\n")) + if not m: + continue + + issue = int(m.group("issue")) + if issue not in updates: + continue + + new_state = updates[issue] + old_state = current_state(m.group("check"), m.group("badge")) + if old_state == new_state: + continue + + render = STATE_RENDER[new_state] + lines[i] = ( + m.group("prefix") + + render["check"] + + m.group("mid") + + render["badge"] + + m.group("body") + + m.group("issue") + + m.group("rest") + + "\n" + ) + changed = True + print(f"#{issue}: [{old_state}] -> [{new_state}]") + + if changed: + with open(ROADMAP_PATH, "w", encoding="utf-8") as f: + f.writelines(lines) + + return changed + + +def main() -> None: + updates = compute_updates() + if not updates: + print("No linked roadmap issue affected by this event — nothing to do.") + changed = False + else: + changed = apply_updates(updates) + if not changed: + print("Matching roadmap line(s) already up to date.") + + github_output = os.environ.get("GITHUB_OUTPUT") + if github_output: + with open(github_output, "a", encoding="utf-8") as f: + f.write(f"changed={'true' if changed else 'false'}\n") + + +if __name__ == "__main__": + main() From ba339a9261bd39fc862b6e889e1bd0e09a8a93a2 Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 23:28:36 +0200 Subject: [PATCH 25/81] Added a reconcile step for manual triggering and scheduled at 04:00 AM --- .github/workflows/sync_roadmap_status.yml | 40 ++++++++++ scripts/roadmap/reconcile_roadmap.py | 96 +++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 scripts/roadmap/reconcile_roadmap.py diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml index 5194817..0acc23f 100644 --- a/.github/workflows/sync_roadmap_status.yml +++ b/.github/workflows/sync_roadmap_status.yml @@ -9,12 +9,19 @@ on: # (already in the event payload) and write to ROADMAP.md on main. pull_request_target: types: [opened, ready_for_review, closed] + # Run reconcile.py on demand ("Run workflow" button) and once a day + # as a safety net against any missed event (e.g. an issue closed + # before its ROADMAP.md line had "— #N" linked to it yet). + workflow_dispatch: {} + schedule: + - cron: "0 4 * * *" permissions: contents: write jobs: sync: + if: github.event_name == 'issues' || github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -39,6 +46,39 @@ jobs: commit_message: "chore: sync roadmap status [skip ci]" file_pattern: ROADMAP.md + - name: Sync Discord + if: steps.update.outputs.changed == 'true' + run: python scripts/roadmap/sync_discord.py + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} + + reconcile: + if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Reconcile ROADMAP.md with issue states + id: update + run: python scripts/roadmap/reconcile_roadmap.py + env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Commit ROADMAP.md + if: steps.update.outputs.changed == 'true' + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: reconcile roadmap status [skip ci]" + file_pattern: ROADMAP.md + - name: Sync Discord if: steps.update.outputs.changed == 'true' run: python scripts/roadmap/sync_discord.py diff --git a/scripts/roadmap/reconcile_roadmap.py b/scripts/roadmap/reconcile_roadmap.py new file mode 100644 index 0000000..930994e --- /dev/null +++ b/scripts/roadmap/reconcile_roadmap.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +""" +Scans every issue already linked in ROADMAP.md ("— #N") and sets its +checkbox to match that issue's CURRENT state on GitHub — closed, +assigned, or neither. + +Use this: + - once, right after linking a batch of issues, to catch anything that + changed *before* the link existed — sync_roadmap.py only reacts to + events on lines that already have "— #N" on them, so a PR merged + before you added the link is invisible to it + - on a schedule, as a safety net in case a future event is ever missed + (a failed workflow run, a webhook delivery hiccup, etc.) + +Unlike sync_roadmap.py, this doesn't look at PR state directly — an +issue's own state (closed / has an assignee) is used as the signal. +That covers the common paths (assigned, merged-and-closed) even for +history that predates the automation. +""" + +import json +import os +import sys +import urllib.error +import urllib.request + +sys.path.insert(0, os.path.dirname(__file__)) +from sync_roadmap import LINE_RE, ROADMAP_PATH, apply_updates # noqa: E402 + + +def find_linked_issues() -> set[int]: + with open(ROADMAP_PATH, encoding="utf-8") as f: + lines = f.readlines() + + issues = set() + for line in lines: + m = LINE_RE.match(line.rstrip("\n")) + if m: + issues.add(int(m.group("issue"))) + return issues + + +def fetch_issue(repo: str, token: str, number: int) -> dict: + url = f"https://api.github.com/repos/{repo}/issues/{number}" + req = urllib.request.Request( + url, + headers={ + "Authorization": f"Bearer {token}", + "Accept": "application/vnd.github+json", + }, + ) + with urllib.request.urlopen(req) as resp: + return json.load(resp) + + +def target_state(issue: dict) -> str: + if issue.get("state") == "closed": + return "x" + if issue.get("assignees"): + return "-" + return " " + + +def main() -> None: + repo = os.environ["GITHUB_REPOSITORY"] + token = os.environ["GITHUB_TOKEN"] + + issue_numbers = find_linked_issues() + if not issue_numbers: + print("No linked issues found in ROADMAP.md.") + return + + updates: dict[int, str] = {} + for number in sorted(issue_numbers): + try: + issue = fetch_issue(repo, token, number) + except urllib.error.HTTPError as e: + print( + f"#{number}: could not fetch issue ({e.code}) — skipping", + file=sys.stderr, + ) + continue + updates[number] = target_state(issue) + + changed = apply_updates(updates) + if not changed: + print("Roadmap already matched issue states.") + + github_output = os.environ.get("GITHUB_OUTPUT") + if github_output: + with open(github_output, "a", encoding="utf-8") as f: + f.write(f"changed={'true' if changed else 'false'}\n") + + +if __name__ == "__main__": + main() From 31b6ff2a06aa6e2ea0218db786af1818c307dce1 Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 23:53:23 +0200 Subject: [PATCH 26/81] Updated workflow to use PAT token for signing the commits to allow bypassing the branch rules --- .github/workflows/sync_roadmap_status.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml index 0acc23f..5a02601 100644 --- a/.github/workflows/sync_roadmap_status.yml +++ b/.github/workflows/sync_roadmap_status.yml @@ -24,9 +24,15 @@ jobs: if: github.event_name == 'issues' || github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: + # Uses a PAT (not the default GITHUB_TOKEN) so the later push is + # attributed to an account the ruleset's bypass list actually + # recognizes. The default token authenticates as github-actions[bot], + # which doesn't hold a real repo "Write" role, so role-based bypass + # entries never apply to it no matter how they're configured. - uses: actions/checkout@v4 with: ref: main + token: ${{ secrets.ROADMAP_PAT }} - uses: actions/setup-python@v5 with: @@ -60,6 +66,7 @@ jobs: - uses: actions/checkout@v4 with: ref: main + token: ${{ secrets.ROADMAP_PAT }} - uses: actions/setup-python@v5 with: From 58454ab3c58c2457621447f686a14531e2d3a775 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:23:19 +0200 Subject: [PATCH 27/81] Improve error handling in sync_discord.py Added error handling for HTTP errors when updating messages. --- scripts/roadmap/sync_discord.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/scripts/roadmap/sync_discord.py b/scripts/roadmap/sync_discord.py index 57a9f67..67d2224 100644 --- a/scripts/roadmap/sync_discord.py +++ b/scripts/roadmap/sync_discord.py @@ -22,6 +22,7 @@ import os import re import sys +import urllib.error import urllib.request ROADMAP_PATH = "ROADMAP.md" @@ -93,14 +94,22 @@ def patch_message(webhook_url: str, message_id: str, embed: dict) -> None: url, data=payload, method="PATCH", - headers={"Content-Type": "application/json"}, + headers={ + "Content-Type": "application/json", + "User-Agent": "ThePythonLedger-RoadmapSync (https://github.com/ThePythonLedger/Curriculum, 1.0)", + }, ) - with urllib.request.urlopen(req) as resp: - if resp.status not in (200, 204): - print( - f"Unexpected status {resp.status} updating message {message_id}", - file=sys.stderr, - ) + try: + with urllib.request.urlopen(req) as resp: + if resp.status not in (200, 204): + print( + f"Unexpected status {resp.status} updating message {message_id}", + file=sys.stderr, + ) + except urllib.error.HTTPError as e: + body = e.read().decode("utf-8", errors="replace") + print(f"HTTP {e.code} updating message {message_id}: {body}", file=sys.stderr) + raise def main() -> None: From 373e1a576fd81b79d1f605f3ffed9d71b38969fd Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:43:32 +0200 Subject: [PATCH 28/81] Update payload to include empty content in patch_message --- scripts/roadmap/sync_discord.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/roadmap/sync_discord.py b/scripts/roadmap/sync_discord.py index 67d2224..85727a1 100644 --- a/scripts/roadmap/sync_discord.py +++ b/scripts/roadmap/sync_discord.py @@ -89,7 +89,7 @@ def build_embed(phases: list[Phase]) -> dict: def patch_message(webhook_url: str, message_id: str, embed: dict) -> None: url = f"{webhook_url}/messages/{message_id}" - payload = json.dumps({"embeds": [embed]}).encode("utf-8") + payload = json.dumps({"content": "", "embeds": [embed]}).encode("utf-8") req = urllib.request.Request( url, data=payload, From d0d0c000cd18a57aefc64b1ff28e38c041dc5755 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:46:27 +0000 Subject: [PATCH 29/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index f03b6d6..c21f994 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -33,6 +33,11 @@ This may be subject to change. * [ ] Sets (WIP) * [ ] Dictionaries (WIP) * [ ] Coprehensions (`list`, `dict` `set`) (WIP) + * [ ] 🚧 Lists — #57 + * [ ] 🚧 Tuples — #58 + * [ ] 🚧 Sets — #59 + * [ ] 🚧 Dictionaries — #60 + * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization * [ ] Functions * [ ] Scope and Namespaces (LEGB rule) From 79b10f1a9ba321cec45ee50b7650482461b3e118 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:08:01 +0000 Subject: [PATCH 30/81] Added contributor(s) name(s) to ROADMAP.md sync scripts and updated ROADMAP.md to include changes in its "legend map". --- ROADMAP.md | 1 + scripts/roadmap/reconcile_roadmap.py | 28 +++--- scripts/roadmap/sync_roadmap.py | 142 +++++++++++++++++---------- 3 files changed, 102 insertions(+), 69 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index c21f994..6b6fdfa 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -5,6 +5,7 @@ This may be subject to change. `[ ]` - no work has been done `[ ] 🚧` - work in progress (assigned / open PR) `[x]` - lesson completed +`👤 name` - who is working on issue ## Roadmap 1. Introduction diff --git a/scripts/roadmap/reconcile_roadmap.py b/scripts/roadmap/reconcile_roadmap.py index 930994e..cb67744 100644 --- a/scripts/roadmap/reconcile_roadmap.py +++ b/scripts/roadmap/reconcile_roadmap.py @@ -17,7 +17,6 @@ That covers the common paths (assigned, merged-and-closed) even for history that predates the automation. """ - import json import os import sys @@ -25,7 +24,13 @@ import urllib.request sys.path.insert(0, os.path.dirname(__file__)) -from sync_roadmap import LINE_RE, ROADMAP_PATH, apply_updates # noqa: E402 +from sync_roadmap import ( # noqa: E402 + LINE_RE, + ROADMAP_PATH, + Update, + apply_updates, + update_from_issue, +) def find_linked_issues() -> set[int]: @@ -53,14 +58,6 @@ def fetch_issue(repo: str, token: str, number: int) -> dict: return json.load(resp) -def target_state(issue: dict) -> str: - if issue.get("state") == "closed": - return "x" - if issue.get("assignees"): - return "-" - return " " - - def main() -> None: repo = os.environ["GITHUB_REPOSITORY"] token = os.environ["GITHUB_TOKEN"] @@ -70,17 +67,14 @@ def main() -> None: print("No linked issues found in ROADMAP.md.") return - updates: dict[int, str] = {} + updates: dict[int, Update] = {} for number in sorted(issue_numbers): try: issue = fetch_issue(repo, token, number) except urllib.error.HTTPError as e: - print( - f"#{number}: could not fetch issue ({e.code}) — skipping", - file=sys.stderr, - ) + print(f"#{number}: could not fetch issue ({e.code}) — skipping", file=sys.stderr) continue - updates[number] = target_state(issue) + updates[number] = update_from_issue(issue) changed = apply_updates(updates) if not changed: @@ -93,4 +87,4 @@ def main() -> None: if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/scripts/roadmap/sync_roadmap.py b/scripts/roadmap/sync_roadmap.py index 45291ba..d2446d3 100644 --- a/scripts/roadmap/sync_roadmap.py +++ b/scripts/roadmap/sync_roadmap.py @@ -4,9 +4,9 @@ change) and updates the matching line in ROADMAP.md to one of three states: - [ ] Lists — #34 not started - [ ] 🚧 Lists — #34 in progress (assigned / open PR) - [x] Lists — #34 done (merged / issue closed) + [ ] Lists — #34 not started + [ ] 🚧 Lists — #34 👤 alice, bob in progress (assigned / open PR) + [x] Lists — #34 done (merged / issue closed) GitHub's task-list rendering only recognizes [ ] and [x] as real, interactive checkboxes — anything else (like a bare [-]) is just @@ -14,6 +14,10 @@ strictly boolean (done / not done), and "in progress" is layered on as a 🚧 badge in the visible text instead of a third bracket state. +While a lesson is in progress, the issue's assignees are listed at the +end of the line after a 👤 marker (plain usernames, no @ mentions). +The names are dropped again once the lesson is done or unassigned. + This only touches roadmap lines that already reference an issue, e.g.: * [ ] Lists — #34 @@ -21,31 +25,47 @@ Lines with no "— #N" suffix are left alone — link an issue to a lesson by adding that suffix, and the automation picks it up from then on. """ - import json import os import re +from typing import NamedTuple ROADMAP_PATH = "ROADMAP.md" WIP_BADGE = "🚧" +ASSIGNEE_MARKER = "👤" -# Internal state codes (unchanged from before): " " = not started, -# "-" = in progress, "x" = done. Only how they're RENDERED changes. +# Internal state codes: " " = not started, "-" = in progress, "x" = done. +# Only how they're RENDERED matters to GitHub's markdown. STATE_RENDER = { " ": {"check": " ", "badge": ""}, "-": {"check": " ", "badge": f"{WIP_BADGE} "}, "x": {"check": "x", "badge": ""}, } -# Matches e.g. " * [ ] 🚧 Lists — #34" and captures the checkbox, -# an optional WIP badge, and the issue number — everything else on -# the line is left untouched. +# Matches e.g. " * [ ] 🚧 Lists — #34 👤 alice" and captures the checkbox, +# an optional WIP badge, and the issue number. `rest` is everything after +# the issue number (including any assignee suffix, handled separately). LINE_RE = re.compile( r"^(?P\s*\*\s*\[)(?P[ x])(?P\]\s*)" rf"(?P{WIP_BADGE}\s*)?" r"(?P.*?—\s*#)(?P\d+)(?P.*)$" ) +# The assignee suffix always sits at the very end of the line. +ASSIGNEE_SUFFIX_RE = re.compile(rf"\s+{ASSIGNEE_MARKER}\s+.*$") + +# Matches "Closes #12", "Fixes #34", "Resolves #7", etc. (repeatable, case-insensitive) +ISSUE_REF_RE = re.compile(r"(?:clos(?:e[sd]?)|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)", re.IGNORECASE) + +HANDLED_ISSUE_ACTIONS = {"assigned", "unassigned", "closed", "reopened"} + + +class Update(NamedTuple): + state: str + # None = keep whatever names are already on the line. PR events use this, + # since a PR payload doesn't carry the linked issue's assignee list. + assignees: list[str] | None = None + def current_state(check: str, badge: str | None) -> str: if check == "x": @@ -53,29 +73,31 @@ def current_state(check: str, badge: str | None) -> str: return "-" if badge else " " -# Matches "Closes #12", "Fixes #34", "Resolves #7", etc. (repeatable, case-insensitive) -ISSUE_REF_RE = re.compile( - r"(?:clos(?:e[sd]?)|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)", re.IGNORECASE -) +def state_for_issue(issue: dict) -> str: + if issue.get("state") == "closed": + return "x" + return "-" if issue.get("assignees") else " " -def marker_for_issue_event(event: dict) -> dict[int, str]: - action = event["action"] - issue_number = event["issue"]["number"] - - if action == "assigned": - return {issue_number: "-"} - if action == "unassigned": - return {issue_number: " "} - if action == "closed": - return {issue_number: "x"} - if action == "reopened": - has_assignee = bool(event["issue"].get("assignees")) - return {issue_number: "-" if has_assignee else " "} - return {} +def assignee_logins(issue: dict) -> list[str]: + return [a["login"] for a in issue.get("assignees") or []] + + +def update_from_issue(issue: dict) -> Update: + """Works for both webhook payloads and REST API issue objects.""" + return Update(state_for_issue(issue), assignee_logins(issue)) + + +def updates_for_issue_event(event: dict) -> dict[int, Update]: + if event["action"] not in HANDLED_ISSUE_ACTIONS: + return {} + issue = event["issue"] + # The issue object reflects the state AFTER the change, so unassigning + # one of two people correctly leaves the line in progress. + return {issue["number"]: update_from_issue(issue)} -def marker_for_pr_event(event: dict) -> dict[int, str]: +def updates_for_pr_event(event: dict) -> dict[int, Update]: action = event["action"] pr = event["pull_request"] body = pr.get("body") or "" @@ -84,13 +106,13 @@ def marker_for_pr_event(event: dict) -> dict[int, str]: return {} if action in ("opened", "ready_for_review"): - marker = "-" + update = Update("-") elif action == "closed": - marker = "x" if pr.get("merged") else "-" + update = Update("x") if pr.get("merged") else Update("-") else: return {} - return {n: marker for n in issue_numbers} + return {n: update for n in issue_numbers} def load_event() -> dict: @@ -98,24 +120,37 @@ def load_event() -> dict: return json.load(f) -def compute_updates() -> dict[int, str]: +def compute_updates() -> dict[int, Update]: event_name = os.environ["GITHUB_EVENT_NAME"] event = load_event() if event_name == "issues": - return marker_for_issue_event(event) - if event_name == "pull_request" or event_name == "pull_request_target": - return marker_for_pr_event(event) + return updates_for_issue_event(event) + if event_name in ("pull_request", "pull_request_target"): + return updates_for_pr_event(event) return {} -def apply_updates(updates: dict[int, str]) -> bool: +def render_suffix(update: Update, existing_suffix: str) -> str: + if update.state != "-": + return "" # names are only shown while a lesson is in progress + if update.assignees is None: + return existing_suffix + if not update.assignees: + return "" + return f" {ASSIGNEE_MARKER} {', '.join(update.assignees)}" + + +def apply_updates(updates: dict[int, Update]) -> bool: with open(ROADMAP_PATH, encoding="utf-8") as f: lines = f.readlines() changed = False for i, line in enumerate(lines): - m = LINE_RE.match(line.rstrip("\n")) + stripped = line.rstrip("\r\n") + eol = line[len(stripped):] + + m = LINE_RE.match(stripped) if not m: continue @@ -123,24 +158,27 @@ def apply_updates(updates: dict[int, str]) -> bool: if issue not in updates: continue - new_state = updates[issue] + update = updates[issue] old_state = current_state(m.group("check"), m.group("badge")) - if old_state == new_state: + render = STATE_RENDER[update.state] + + rest = m.group("rest") + existing = ASSIGNEE_SUFFIX_RE.search(rest) + rest_base = ASSIGNEE_SUFFIX_RE.sub("", rest) + suffix = render_suffix(update, existing.group(0) if existing else "") + if suffix: + rest_base = rest_base.rstrip() # no double space before the 👤 + + new_line = ( + m.group("prefix") + render["check"] + m.group("mid") + render["badge"] + + m.group("body") + m.group("issue") + rest_base + suffix + eol + ) + if new_line == line: continue - render = STATE_RENDER[new_state] - lines[i] = ( - m.group("prefix") - + render["check"] - + m.group("mid") - + render["badge"] - + m.group("body") - + m.group("issue") - + m.group("rest") - + "\n" - ) + lines[i] = new_line changed = True - print(f"#{issue}: [{old_state}] -> [{new_state}]") + print(f"#{issue}: [{old_state}] -> [{update.state}]{suffix}") if changed: with open(ROADMAP_PATH, "w", encoding="utf-8") as f: @@ -166,4 +204,4 @@ def main() -> None: if __name__ == "__main__": - main() + main() \ No newline at end of file From f95c6b5b87df7393e6e3f32c2008ebe9e4ad4868 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 13 Sep 2026 16:57:49 +0200 Subject: [PATCH 31/81] Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson --- curriculum/05-data-structures/05-comprehensions.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md index e6e0b86..d9545f5 100644 --- a/curriculum/05-data-structures/05-comprehensions.md +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -171,5 +171,4 @@ Use them with caution and remember: ## Assignment {#assignment} -## What's Next {#next-lesson} -Comprehensions are very useful in everyday life as a Python programmer, but there is one thing that is universal across all languages, so let's start a new chapter; *code organization*. First thing to learn are **functions** which enable us to write modular code. +## What's Next {#next-lesson} \ No newline at end of file From 244e4641097d20f7f9337a4b5344c41931488a26 Mon Sep 17 00:00:00 2001 From: amotech Date: Fri, 2 Oct 2026 11:02:52 +0000 Subject: [PATCH 32/81] ask4help update v0.2 --- .gitignore | 4 +++- .../01-introduction/03-asking-for-help.md | 23 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index a22f7b1..e6df35e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .obsidian/** .obsidian -.trash \ No newline at end of file +.trash +.git-bestPractices +.vscode/extensions.json \ No newline at end of file diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index 363c961..3fd10ba 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -38,22 +38,31 @@ Before you ask anything check if: ### 2. The Question space 📰❔ -Paste your code below: +Carefully study the `code` below: -′′′python +```python -import A +var1 = "12" +var2 = 12 -′′′ +results = var1 + var2 #this raises an error, why?—you will learn how to go about finding a soln—to the why, how, &what. + +``` +Your `code` should follow the pep8 style, as well as the `syntax` should be valid so you get an appropriate help response. ### 3. How to Format Your Code 🔃 - You are required to format your code (_python code_) using the markdown language in order to get the appropriate responses to your help requests. -... + +Steps to format your code: +- Type in three of the ` ``` ` character(three) to open it and close with another three of the ` ``` ` character. +- In between the opening and closing character sets, type `python` and enter a `space` character. You should have something like this: ` ```python ``` ` . +- Press `Enter` to go to a new line, now you are set to paste your `code` for submission—make sure the code syntax is valid, and is same as the one which raised the error; that is the `indentaion`, `spacing`, and `others` are all same. + ### 4. What to Expect Next ➡ Once you have submitted your help request, sit down tight and the appropriate help will be sent straight to you. -If unfortunately the help response delays or never comes, use the next approach which is _WHO TO ASK_. +If unfortunately the help response delays or never comes, use the next approach which is _Who To Ask_. ## Who to Ask for Help 🧔🏻❔ @@ -64,7 +73,7 @@ subs: * Ask an Ai agent ### 1. Ask Yourself Before Anyone -You may say, why myself, i don't know?—Ofcourse you know all the answers to your own questions most of the times. **Ask yourself why, why did the error come; Ask yourself how, how did the error come; and Ask yourself what, what brought up a particular error** :(. You are not actually finding the correct solution to the cause of the error with these questions overnight (as if it was a magic :)), *but* what you are doing is you are training your thinking which may help you think creatively gradually—to solve future problems. "Problem solving requires a creative and effective thinking"—Baldwin.J,. college success(2021). +You may say, why myself, i don't know?—Ofcourse you know all the answers to your own questions most of the times. **Ask yourself why, why did the error come; Ask yourself how, how did the error come; and Ask yourself what, what brought up a particular error** :(. You are not actually finding the correct solution to the cause of the error with these questions overnight (as if it was a magic :)), **but** what you are doing is you are training your thinking, which may help you think creatively gradually—to solve future problems. "Problem solving requires a creative and effective thinking"—Baldwin.J,. college success(2021). After you have had your answers to those three question, store them safely as we will learn how they might become useful later in this lesson. From 3d2eba22eb5398a9f717b8a33b089bd4845a58cc Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 22:51:49 +0200 Subject: [PATCH 33/81] Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow. --- scripts/roadmap/sync_roadmap.py | 171 +++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 1 deletion(-) diff --git a/scripts/roadmap/sync_roadmap.py b/scripts/roadmap/sync_roadmap.py index d2446d3..3b93a51 100644 --- a/scripts/roadmap/sync_roadmap.py +++ b/scripts/roadmap/sync_roadmap.py @@ -204,4 +204,173 @@ def main() -> None: if __name__ == "__main__": - main() \ No newline at end of file + main() +#!/usr/bin/env python3 +""" +Reads the GitHub event that triggered this workflow run (an issue or PR +change) and updates the matching line in ROADMAP.md to one of three +states: + + [ ] Lists — #34 not started + [ ] 🚧 Lists — #34 in progress (assigned / open PR) + [x] Lists — #34 done (merged / issue closed) + +GitHub's task-list rendering only recognizes [ ] and [x] as real, +interactive checkboxes — anything else (like a bare [-]) is just +literal text with no checkbox widget. So the checkbox itself stays +strictly boolean (done / not done), and "in progress" is layered on +as a 🚧 badge in the visible text instead of a third bracket state. + +This only touches roadmap lines that already reference an issue, e.g.: + + * [ ] Lists — #34 + +Lines with no "— #N" suffix are left alone — link an issue to a lesson +by adding that suffix, and the automation picks it up from then on. +""" + +import json +import os +import re + +ROADMAP_PATH = "ROADMAP.md" +WIP_BADGE = "🚧" + +# Internal state codes (unchanged from before): " " = not started, +# "-" = in progress, "x" = done. Only how they're RENDERED changes. +STATE_RENDER = { + " ": {"check": " ", "badge": ""}, + "-": {"check": " ", "badge": f"{WIP_BADGE} "}, + "x": {"check": "x", "badge": ""}, +} + +# Matches e.g. " * [ ] 🚧 Lists — #34" and captures the checkbox, +# an optional WIP badge, and the issue number — everything else on +# the line is left untouched. +LINE_RE = re.compile( + r"^(?P\s*\*\s*\[)(?P[ x])(?P\]\s*)" + rf"(?P{WIP_BADGE}\s*)?" + r"(?P.*?—\s*#)(?P\d+)(?P.*)$" +) + + +def current_state(check: str, badge: str | None) -> str: + if check == "x": + return "x" + return "-" if badge else " " + + +# Matches "Closes #12", "Fixes #34", "Resolves #7", etc. (repeatable, case-insensitive) +ISSUE_REF_RE = re.compile( + r"(?:clos(?:e[sd]?)|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)", re.IGNORECASE +) + + +def marker_for_issue_event(event: dict) -> dict[int, str]: + action = event["action"] + issue_number = event["issue"]["number"] + + if action == "assigned": + return {issue_number: "-"} + if action == "unassigned": + return {issue_number: " "} + if action == "closed": + return {issue_number: "x"} + if action == "reopened": + has_assignee = bool(event["issue"].get("assignees")) + return {issue_number: "-" if has_assignee else " "} + return {} + + +def marker_for_pr_event(event: dict) -> dict[int, str]: + action = event["action"] + pr = event["pull_request"] + body = pr.get("body") or "" + issue_numbers = {int(n) for n in ISSUE_REF_RE.findall(body)} + if not issue_numbers: + return {} + + if action in ("opened", "ready_for_review"): + marker = "-" + elif action == "closed": + marker = "x" if pr.get("merged") else "-" + else: + return {} + + return {n: marker for n in issue_numbers} + + +def load_event() -> dict: + with open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8") as f: + return json.load(f) + + +def compute_updates() -> dict[int, str]: + event_name = os.environ["GITHUB_EVENT_NAME"] + event = load_event() + + if event_name == "issues": + return marker_for_issue_event(event) + if event_name == "pull_request" or event_name == "pull_request_target": + return marker_for_pr_event(event) + return {} + + +def apply_updates(updates: dict[int, str]) -> bool: + with open(ROADMAP_PATH, encoding="utf-8") as f: + lines = f.readlines() + + changed = False + for i, line in enumerate(lines): + m = LINE_RE.match(line.rstrip("\n")) + if not m: + continue + + issue = int(m.group("issue")) + if issue not in updates: + continue + + new_state = updates[issue] + old_state = current_state(m.group("check"), m.group("badge")) + if old_state == new_state: + continue + + render = STATE_RENDER[new_state] + lines[i] = ( + m.group("prefix") + + render["check"] + + m.group("mid") + + render["badge"] + + m.group("body") + + m.group("issue") + + m.group("rest") + + "\n" + ) + changed = True + print(f"#{issue}: [{old_state}] -> [{new_state}]") + + if changed: + with open(ROADMAP_PATH, "w", encoding="utf-8") as f: + f.writelines(lines) + + return changed + + +def main() -> None: + updates = compute_updates() + if not updates: + print("No linked roadmap issue affected by this event — nothing to do.") + changed = False + else: + changed = apply_updates(updates) + if not changed: + print("Matching roadmap line(s) already up to date.") + + github_output = os.environ.get("GITHUB_OUTPUT") + if github_output: + with open(github_output, "a", encoding="utf-8") as f: + f.write(f"changed={'true' if changed else 'false'}\n") + + +if __name__ == "__main__": + main() From 1cb9de04f3e031d3960a6384303b552e187ee9db Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 23:28:36 +0200 Subject: [PATCH 34/81] Added a reconcile step for manual triggering and scheduled at 04:00 AM --- .github/workflows/sync_roadmap_status.yml | 34 ----------------------- scripts/roadmap/reconcile_roadmap.py | 28 +++++++++++-------- 2 files changed, 17 insertions(+), 45 deletions(-) diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml index 5a02601..56cd835 100644 --- a/.github/workflows/sync_roadmap_status.yml +++ b/.github/workflows/sync_roadmap_status.yml @@ -52,40 +52,6 @@ jobs: commit_message: "chore: sync roadmap status [skip ci]" file_pattern: ROADMAP.md - - name: Sync Discord - if: steps.update.outputs.changed == 'true' - run: python scripts/roadmap/sync_discord.py - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} - - reconcile: - if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: main - token: ${{ secrets.ROADMAP_PAT }} - - - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - - name: Reconcile ROADMAP.md with issue states - id: update - run: python scripts/roadmap/reconcile_roadmap.py - env: - GITHUB_REPOSITORY: ${{ github.repository }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Commit ROADMAP.md - if: steps.update.outputs.changed == 'true' - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "chore: reconcile roadmap status [skip ci]" - file_pattern: ROADMAP.md - - name: Sync Discord if: steps.update.outputs.changed == 'true' run: python scripts/roadmap/sync_discord.py diff --git a/scripts/roadmap/reconcile_roadmap.py b/scripts/roadmap/reconcile_roadmap.py index cb67744..930994e 100644 --- a/scripts/roadmap/reconcile_roadmap.py +++ b/scripts/roadmap/reconcile_roadmap.py @@ -17,6 +17,7 @@ That covers the common paths (assigned, merged-and-closed) even for history that predates the automation. """ + import json import os import sys @@ -24,13 +25,7 @@ import urllib.request sys.path.insert(0, os.path.dirname(__file__)) -from sync_roadmap import ( # noqa: E402 - LINE_RE, - ROADMAP_PATH, - Update, - apply_updates, - update_from_issue, -) +from sync_roadmap import LINE_RE, ROADMAP_PATH, apply_updates # noqa: E402 def find_linked_issues() -> set[int]: @@ -58,6 +53,14 @@ def fetch_issue(repo: str, token: str, number: int) -> dict: return json.load(resp) +def target_state(issue: dict) -> str: + if issue.get("state") == "closed": + return "x" + if issue.get("assignees"): + return "-" + return " " + + def main() -> None: repo = os.environ["GITHUB_REPOSITORY"] token = os.environ["GITHUB_TOKEN"] @@ -67,14 +70,17 @@ def main() -> None: print("No linked issues found in ROADMAP.md.") return - updates: dict[int, Update] = {} + updates: dict[int, str] = {} for number in sorted(issue_numbers): try: issue = fetch_issue(repo, token, number) except urllib.error.HTTPError as e: - print(f"#{number}: could not fetch issue ({e.code}) — skipping", file=sys.stderr) + print( + f"#{number}: could not fetch issue ({e.code}) — skipping", + file=sys.stderr, + ) continue - updates[number] = update_from_issue(issue) + updates[number] = target_state(issue) changed = apply_updates(updates) if not changed: @@ -87,4 +93,4 @@ def main() -> None: if __name__ == "__main__": - main() \ No newline at end of file + main() From e6be916b1ce76559940bb52edb906d369faea776 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:56:05 +0000 Subject: [PATCH 35/81] chore: reconcile roadmap status [skip ci] --- ROADMAP.md | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 6b6fdfa..e19e32d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -10,9 +10,9 @@ This may be subject to change. ## Roadmap 1. Introduction * [x] How course works? - * [ ] Motivation and Mindset - * [ ] Asking for Help (WIP) - * [x] Join the Community + * [x] Motivation and Mindset + * [ ] Asking for Help — #32 + * [ ] Join the Community — #33 * [x] Computer Science basics, Programming and Python 2. Prerequisites * [x] Software Installation @@ -29,25 +29,20 @@ This may be subject to change. * [x] User Input and Conditionals * [x] Loops 5. Data Structures - * [ ] Lists (WIP) - * [ ] Tuples (WIP) - * [ ] Sets (WIP) - * [ ] Dictionaries (WIP) - * [ ] Coprehensions (`list`, `dict` `set`) (WIP) - * [ ] 🚧 Lists — #57 - * [ ] 🚧 Tuples — #58 - * [ ] 🚧 Sets — #59 - * [ ] 🚧 Dictionaries — #60 - * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 + * [ ] Lists — #57 + * [ ] Tuples — #58 + * [ ] Sets — #59 + * [ ] Dictionaries — #60 + * [ ] Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization - * [ ] Functions - * [ ] Scope and Namespaces (LEGB rule) - * [ ] Type Hints - * [ ] Modules + * [ ] Functions — #62 + * [ ] Scope and Namespaces (LEGB rule) — #63 + * [ ] Type Hints — #64 + * [ ] Modules — #65 7. Capstone Project 1 - * [ ] Problem Solving - * [ ] Problem Solving - Fizz-Buzz Example - * [ ] Capstone Project - **Hangman game** + * [ ] Problem Solving — #66 + * [ ] Problem Solving - Fizz-Buzz Example — #67 + * [ ] Capstone Project - **Hangman game** — #68 8. Errors, Debugging, I/O * [ ] Understanding Errors and Error Handling * [ ] `logging` module From 939887702b2801897b73da5bc6d8252f788564fb Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:57:39 +0000 Subject: [PATCH 36/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index e19e32d..94cf366 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -35,10 +35,10 @@ This may be subject to change. * [ ] Dictionaries — #60 * [ ] Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization - * [ ] Functions — #62 - * [ ] Scope and Namespaces (LEGB rule) — #63 - * [ ] Type Hints — #64 - * [ ] Modules — #65 + * [ ] 🚧 Functions — #62 + * [ ] 🚧 Scope and Namespaces (LEGB rule) — #63 + * [ ] 🚧 Type Hints — #64 + * [ ] 🚧 Modules — #65 7. Capstone Project 1 * [ ] Problem Solving — #66 * [ ] Problem Solving - Fizz-Buzz Example — #67 From 7202349ceabd71c505159192e9c4fe7df5c316e9 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:58:22 +0000 Subject: [PATCH 37/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 94cf366..dfdb733 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -35,8 +35,8 @@ This may be subject to change. * [ ] Dictionaries — #60 * [ ] Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization - * [ ] 🚧 Functions — #62 - * [ ] 🚧 Scope and Namespaces (LEGB rule) — #63 + * [ ] Functions — #62 + * [ ] Scope and Namespaces (LEGB rule) — #63 * [ ] 🚧 Type Hints — #64 * [ ] 🚧 Modules — #65 7. Capstone Project 1 From a076b5418fd06cb56153b06299591607a64477d6 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:13:57 +0000 Subject: [PATCH 38/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index dfdb733..0232d7b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -29,10 +29,10 @@ This may be subject to change. * [x] User Input and Conditionals * [x] Loops 5. Data Structures - * [ ] Lists — #57 - * [ ] Tuples — #58 - * [ ] Sets — #59 - * [ ] Dictionaries — #60 + * [ ] 🚧 Lists — #57 + * [ ] 🚧 Tuples — #58 + * [ ] 🚧 Sets — #59 + * [ ] 🚧 Dictionaries — #60 * [ ] Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization * [ ] Functions — #62 From df82d82dc37616885ff14aa2cc069f518bfaff31 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:25:28 +0000 Subject: [PATCH 39/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0232d7b..d92141a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -33,7 +33,7 @@ This may be subject to change. * [ ] 🚧 Tuples — #58 * [ ] 🚧 Sets — #59 * [ ] 🚧 Dictionaries — #60 - * [ ] Coprehensions (`list`, `dict` `set`) — #61 + * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization * [ ] Functions — #62 * [ ] Scope and Namespaces (LEGB rule) — #63 From 39f133c2443d001439e2fd0beb20b32296e40754 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:44:22 +0000 Subject: [PATCH 40/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index d92141a..0232d7b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -33,7 +33,7 @@ This may be subject to change. * [ ] 🚧 Tuples — #58 * [ ] 🚧 Sets — #59 * [ ] 🚧 Dictionaries — #60 - * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 + * [ ] Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization * [ ] Functions — #62 * [ ] Scope and Namespaces (LEGB rule) — #63 From 873f976d6f6a497c3be58749fd4cf14034a88d96 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:46:27 +0000 Subject: [PATCH 41/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0232d7b..d92141a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -33,7 +33,7 @@ This may be subject to change. * [ ] 🚧 Tuples — #58 * [ ] 🚧 Sets — #59 * [ ] 🚧 Dictionaries — #60 - * [ ] Coprehensions (`list`, `dict` `set`) — #61 + * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization * [ ] Functions — #62 * [ ] Scope and Namespaces (LEGB rule) — #63 From 62d67f1082e1b56bb736ce68d0055080f0ce0b07 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:08:45 +0000 Subject: [PATCH 42/81] chore: reconcile roadmap status [skip ci] --- ROADMAP.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index d92141a..039f051 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -29,11 +29,11 @@ This may be subject to change. * [x] User Input and Conditionals * [x] Loops 5. Data Structures - * [ ] 🚧 Lists — #57 - * [ ] 🚧 Tuples — #58 - * [ ] 🚧 Sets — #59 - * [ ] 🚧 Dictionaries — #60 - * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 + * [ ] 🚧 Lists — #57 👤 razorblade23 + * [ ] 🚧 Tuples — #58 👤 razorblade23 + * [ ] 🚧 Sets — #59 👤 razorblade23 + * [ ] 🚧 Dictionaries — #60 👤 razorblade23 + * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 👤 razorblade23 6. Code Organization * [ ] Functions — #62 * [ ] Scope and Namespaces (LEGB rule) — #63 From ccd78aff7af082e4500d6a67cdf187bbff5f5c73 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Thu, 1 Oct 2026 05:51:56 +0000 Subject: [PATCH 43/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 039f051..e2c351a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -35,7 +35,7 @@ This may be subject to change. * [ ] 🚧 Dictionaries — #60 👤 razorblade23 * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 👤 razorblade23 6. Code Organization - * [ ] Functions — #62 + * [ ] 🚧 Functions — #62 👤 tajirdev * [ ] Scope and Namespaces (LEGB rule) — #63 * [ ] 🚧 Type Hints — #64 * [ ] 🚧 Modules — #65 From dd8133f88eb7d6e3461cbae134d59825b96ad6d2 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sat, 12 Sep 2026 09:33:50 +0200 Subject: [PATCH 44/81] Updated lists lessons and ROADMAPmd --- ROADMAP.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index e2c351a..7bd9de8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -129,6 +129,7 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module +<<<<<<< HEAD * [ ] `re` module 13. Third-party Modules * [ ] Virtual Environments @@ -167,3 +168,22 @@ This may be subject to change. * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) 15. Capstone Project 4 * [ ] Capstone Project +======= +10. Third-party Modules + * [ ] Virtual Environments + * [ ] Using `pip` and `requirements.txt` + * [ ] Creating python package - `pyproject.toml` file +11. Capstone Project 2 + * [ ] Clean Code Priciples + * [ ] Capstone Project +12. Object Oriented Programming - Part 1 + * [ ] Introduction to classes and instances + * [ ] Methods (instance, class, static) + * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) +13. Capstone Project 3 + * [ ] Capstone Project +14. Object Oriented Programming - Part 2 + * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) +15. Capstone Project 4 + * [ ] Capstone Project +>>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) From ad12403b3dad16039574a0ff24593fcdd2562874 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 13 Sep 2026 16:57:49 +0200 Subject: [PATCH 45/81] Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson --- ROADMAP.md | 14 +++++++++----- curriculum/05-data-structures/05-comprehensions.md | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 7bd9de8..89457b8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -129,6 +129,7 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module +<<<<<<< HEAD <<<<<<< HEAD * [ ] `re` module 13. Third-party Modules @@ -170,20 +171,23 @@ This may be subject to change. * [ ] Capstone Project ======= 10. Third-party Modules +======= +9. Third-party Modules +>>>>>>> 71088b3 (Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson) * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file -11. Capstone Project 2 +10. Capstone Project 2 * [ ] Clean Code Priciples * [ ] Capstone Project -12. Object Oriented Programming - Part 1 +11. Object Oriented Programming - Part 1 * [ ] Introduction to classes and instances * [ ] Methods (instance, class, static) * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -13. Capstone Project 3 +12. Capstone Project 3 * [ ] Capstone Project -14. Object Oriented Programming - Part 2 +13. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -15. Capstone Project 4 +14. Capstone Project 4 * [ ] Capstone Project >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) diff --git a/curriculum/05-data-structures/05-comprehensions.md b/curriculum/05-data-structures/05-comprehensions.md index d9545f5..1aff5dd 100644 --- a/curriculum/05-data-structures/05-comprehensions.md +++ b/curriculum/05-data-structures/05-comprehensions.md @@ -171,4 +171,5 @@ Use them with caution and remember: ## Assignment {#assignment} -## What's Next {#next-lesson} \ No newline at end of file +## What's Next {#next-lesson} +Coprehensions are very useful in every day life as a Python programmer, but there is one thing that is universal accross all languages, so let's start a new chapter; *code organization*. First thing to learn are **functions** which enable us to write modular code. \ No newline at end of file From 680c44cadca8110c3e240c435fadeba204129426 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 16 Sep 2026 16:21:03 +0200 Subject: [PATCH 46/81] Couple of changes to lesson and better ROADMAP.md --- ROADMAP.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 89457b8..dd3323c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -29,11 +29,11 @@ This may be subject to change. * [x] User Input and Conditionals * [x] Loops 5. Data Structures - * [ ] 🚧 Lists — #57 👤 razorblade23 - * [ ] 🚧 Tuples — #58 👤 razorblade23 - * [ ] 🚧 Sets — #59 👤 razorblade23 - * [ ] 🚧 Dictionaries — #60 👤 razorblade23 - * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 👤 razorblade23 + * [x] Lists (WIP) + * [x] Tuples (WIP) + * [x] Sets (WIP) + * [x] Dictionaries (WIP) + * [x] Coprehensions (`list`, `dict` `set`) (WIP) 6. Code Organization * [ ] 🚧 Functions — #62 👤 tajirdev * [ ] Scope and Namespaces (LEGB rule) — #63 From 5ceb880e8a1c437d5db018439b84ebd7d33305e5 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 16 Sep 2026 22:56:24 +0200 Subject: [PATCH 47/81] Updated roadmap with missing topics --- ROADMAP.md | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index dd3323c..d2bfb6e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -44,22 +44,14 @@ This may be subject to change. * [ ] Problem Solving - Fizz-Buzz Example — #67 * [ ] Capstone Project - **Hangman game** — #68 8. Errors, Debugging, I/O + * [ ] Functions + * [ ] Scope and Namespaces (LEGB rule) * [ ] Understanding Errors and Error Handling - * [ ] `logging` module - * [ ] Debugging tehniques * [ ] File Handling -9. Capstone Project 2 - * [ ] Git Workflow: Branches and Pull Requests - * [ ] Revisiting Project 1 (hangman game): - * Creating branch, adding features, merging back to `main` - * Loading *words* from external file - * Catching and logging errors - * [ ] Capstone Project -10. Intermediate Python - * [ ] Decorators - * [ ] Generators - * [ ] Context Managers -11. Capstone Project 3 + * [ ] Modules +7. Capstone Project 1 + * [ ] Problem Solving + * [ ] Problem Solving - Fizz-Buzz Example * [ ] Capstone Project 12. Built-in and Modules * [-] Data Structures @@ -129,10 +121,7 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module -<<<<<<< HEAD -<<<<<<< HEAD - * [ ] `re` module -13. Third-party Modules +9. Third-party Modules * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file From 0c0a550c519aab2192f1e77b1ba4546cfede0460 Mon Sep 17 00:00:00 2001 From: amotech Date: Mon, 28 Sep 2026 15:41:50 +0000 Subject: [PATCH 48/81] test3 --- curriculum/01-introduction/03-asking-for-help.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index 3fd10ba..7e4d9b8 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -50,7 +50,7 @@ results = var1 + var2 #this raises an error, why?—you will learn how to go abo ``` Your `code` should follow the pep8 style, as well as the `syntax` should be valid so you get an appropriate help response. -### 3. How to Format Your Code 🔃 +### 3. How to Format Your Code 🔃 - You are required to format your code (_python code_) using the markdown language in order to get the appropriate responses to your help requests. Steps to format your code: From fa416b9dfa0fc1675b7e91421e812d3e2a8558af Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 22:51:49 +0200 Subject: [PATCH 49/81] Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow. --- scripts/roadmap/sync_roadmap.py | 169 -------------------------------- 1 file changed, 169 deletions(-) diff --git a/scripts/roadmap/sync_roadmap.py b/scripts/roadmap/sync_roadmap.py index 3b93a51..f784676 100644 --- a/scripts/roadmap/sync_roadmap.py +++ b/scripts/roadmap/sync_roadmap.py @@ -203,174 +203,5 @@ def main() -> None: f.write(f"changed={'true' if changed else 'false'}\n") -if __name__ == "__main__": - main() -#!/usr/bin/env python3 -""" -Reads the GitHub event that triggered this workflow run (an issue or PR -change) and updates the matching line in ROADMAP.md to one of three -states: - - [ ] Lists — #34 not started - [ ] 🚧 Lists — #34 in progress (assigned / open PR) - [x] Lists — #34 done (merged / issue closed) - -GitHub's task-list rendering only recognizes [ ] and [x] as real, -interactive checkboxes — anything else (like a bare [-]) is just -literal text with no checkbox widget. So the checkbox itself stays -strictly boolean (done / not done), and "in progress" is layered on -as a 🚧 badge in the visible text instead of a third bracket state. - -This only touches roadmap lines that already reference an issue, e.g.: - - * [ ] Lists — #34 - -Lines with no "— #N" suffix are left alone — link an issue to a lesson -by adding that suffix, and the automation picks it up from then on. -""" - -import json -import os -import re - -ROADMAP_PATH = "ROADMAP.md" -WIP_BADGE = "🚧" - -# Internal state codes (unchanged from before): " " = not started, -# "-" = in progress, "x" = done. Only how they're RENDERED changes. -STATE_RENDER = { - " ": {"check": " ", "badge": ""}, - "-": {"check": " ", "badge": f"{WIP_BADGE} "}, - "x": {"check": "x", "badge": ""}, -} - -# Matches e.g. " * [ ] 🚧 Lists — #34" and captures the checkbox, -# an optional WIP badge, and the issue number — everything else on -# the line is left untouched. -LINE_RE = re.compile( - r"^(?P\s*\*\s*\[)(?P[ x])(?P\]\s*)" - rf"(?P{WIP_BADGE}\s*)?" - r"(?P.*?—\s*#)(?P\d+)(?P.*)$" -) - - -def current_state(check: str, badge: str | None) -> str: - if check == "x": - return "x" - return "-" if badge else " " - - -# Matches "Closes #12", "Fixes #34", "Resolves #7", etc. (repeatable, case-insensitive) -ISSUE_REF_RE = re.compile( - r"(?:clos(?:e[sd]?)|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)", re.IGNORECASE -) - - -def marker_for_issue_event(event: dict) -> dict[int, str]: - action = event["action"] - issue_number = event["issue"]["number"] - - if action == "assigned": - return {issue_number: "-"} - if action == "unassigned": - return {issue_number: " "} - if action == "closed": - return {issue_number: "x"} - if action == "reopened": - has_assignee = bool(event["issue"].get("assignees")) - return {issue_number: "-" if has_assignee else " "} - return {} - - -def marker_for_pr_event(event: dict) -> dict[int, str]: - action = event["action"] - pr = event["pull_request"] - body = pr.get("body") or "" - issue_numbers = {int(n) for n in ISSUE_REF_RE.findall(body)} - if not issue_numbers: - return {} - - if action in ("opened", "ready_for_review"): - marker = "-" - elif action == "closed": - marker = "x" if pr.get("merged") else "-" - else: - return {} - - return {n: marker for n in issue_numbers} - - -def load_event() -> dict: - with open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8") as f: - return json.load(f) - - -def compute_updates() -> dict[int, str]: - event_name = os.environ["GITHUB_EVENT_NAME"] - event = load_event() - - if event_name == "issues": - return marker_for_issue_event(event) - if event_name == "pull_request" or event_name == "pull_request_target": - return marker_for_pr_event(event) - return {} - - -def apply_updates(updates: dict[int, str]) -> bool: - with open(ROADMAP_PATH, encoding="utf-8") as f: - lines = f.readlines() - - changed = False - for i, line in enumerate(lines): - m = LINE_RE.match(line.rstrip("\n")) - if not m: - continue - - issue = int(m.group("issue")) - if issue not in updates: - continue - - new_state = updates[issue] - old_state = current_state(m.group("check"), m.group("badge")) - if old_state == new_state: - continue - - render = STATE_RENDER[new_state] - lines[i] = ( - m.group("prefix") - + render["check"] - + m.group("mid") - + render["badge"] - + m.group("body") - + m.group("issue") - + m.group("rest") - + "\n" - ) - changed = True - print(f"#{issue}: [{old_state}] -> [{new_state}]") - - if changed: - with open(ROADMAP_PATH, "w", encoding="utf-8") as f: - f.writelines(lines) - - return changed - - -def main() -> None: - updates = compute_updates() - if not updates: - print("No linked roadmap issue affected by this event — nothing to do.") - changed = False - else: - changed = apply_updates(updates) - if not changed: - print("Matching roadmap line(s) already up to date.") - - github_output = os.environ.get("GITHUB_OUTPUT") - if github_output: - with open(github_output, "a", encoding="utf-8") as f: - f.write(f"changed={'true' if changed else 'false'}\n") - - if __name__ == "__main__": main() From ae56c1e8b2a0624ba6a283f8f35523e5a1a03824 Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 22:51:49 +0200 Subject: [PATCH 50/81] Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow. --- .github/workflows/sync_roadmap_status.yml | 11 ++ ROADMAP.md | 148 ++-------------------- scripts/roadmap/sync_discord.py | 18 +++ scripts/roadmap/sync_roadmap.py | 106 ++++++++++++++++ 4 files changed, 144 insertions(+), 139 deletions(-) diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml index 56cd835..122664a 100644 --- a/.github/workflows/sync_roadmap_status.yml +++ b/.github/workflows/sync_roadmap_status.yml @@ -9,18 +9,22 @@ on: # (already in the event payload) and write to ROADMAP.md on main. pull_request_target: types: [opened, ready_for_review, closed] +<<<<<<< HEAD # Run reconcile.py on demand ("Run workflow" button) and once a day # as a safety net against any missed event (e.g. an issue closed # before its ROADMAP.md line had "— #N" linked to it yet). workflow_dispatch: {} schedule: - cron: "0 4 * * *" +======= +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) permissions: contents: write jobs: sync: +<<<<<<< HEAD if: github.event_name == 'issues' || github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: @@ -33,6 +37,13 @@ jobs: with: ref: main token: ${{ secrets.ROADMAP_PAT }} +======= + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) - uses: actions/setup-python@v5 with: diff --git a/ROADMAP.md b/ROADMAP.md index d2bfb6e..e51b7bc 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -11,14 +11,14 @@ This may be subject to change. 1. Introduction * [x] How course works? * [x] Motivation and Mindset - * [ ] Asking for Help — #32 - * [ ] Join the Community — #33 - * [x] Computer Science basics, Programming and Python -2. Prerequisites - * [x] Software Installation - * [x] Text and Code Editors - * [x] Command Line Basics - * [x] Python - REPL vs Scripts + * [ ] Asking for help + * [ ] Join the Community + * [x] Computers and Programming Languages (CS Basics) +2. Prerequisites + * [x] Installation of required software + * [x] Text Editor basics + * [x] Command Line basics + * [x] Python - What is it? REPL vs Scripts 3. Git Basics * [x] Introduction to Git * [x] Setting up Git and Github @@ -28,32 +28,6 @@ This may be subject to change. * [x] Arithmetic and String Operations, Comparisons * [x] User Input and Conditionals * [x] Loops -5. Data Structures - * [x] Lists (WIP) - * [x] Tuples (WIP) - * [x] Sets (WIP) - * [x] Dictionaries (WIP) - * [x] Coprehensions (`list`, `dict` `set`) (WIP) -6. Code Organization - * [ ] 🚧 Functions — #62 👤 tajirdev - * [ ] Scope and Namespaces (LEGB rule) — #63 - * [ ] 🚧 Type Hints — #64 - * [ ] 🚧 Modules — #65 -7. Capstone Project 1 - * [ ] Problem Solving — #66 - * [ ] Problem Solving - Fizz-Buzz Example — #67 - * [ ] Capstone Project - **Hangman game** — #68 -8. Errors, Debugging, I/O - * [ ] Functions - * [ ] Scope and Namespaces (LEGB rule) - * [ ] Understanding Errors and Error Handling - * [ ] File Handling - * [ ] Modules -7. Capstone Project 1 - * [ ] Problem Solving - * [ ] Problem Solving - Fizz-Buzz Example - * [ ] Capstone Project -12. Built-in and Modules * [-] Data Structures * [-] List * [-] Tuple @@ -75,108 +49,4 @@ This may be subject to change. * [ ] Installation of third party libraries * [ ] Working with APIs * [ ] Project 3 - *probably: * weather app -7. Working on Projects, Solving bugs, Reading errors - * [ ] Motivation and Mindset - * [ ] Asking for Help (WIP) - * [x] Join the Community - * [x] Computer Science basics, Programming and Python -2. Prerequisites - * [x] Software Installation - * [x] Text and Code Editors - * [x] Command Line Basics - * [x] Python - REPL vs Scripts -3. Git Basics - * [x] Introduction to Git - * [x] Setting up Git and Github - * [x] Git Basics -4. Foundations - * [x] Output, Variables, Core Datatypes - * [x] Arithmetic and String Operations, Comparisons - * [x] User Input and Conditionals - * [x] Loops -5. Data Structures - * [x] Lists - * [x] Tuples - * [x] Sets - * [x] Dictionaries -6. Comprehensions - * [ ] List Coprehension - * [ ] Set Coprehension - * [ ] Dict Coprehension -7. Code Organization - * [ ] Functions - * [ ] Scope and Namespaces (LEGB rule) - * [ ] Understanding Errors and Error Handling - * [ ] File Handling - * [ ] Modules -8. Capstone Project 1 - * [ ] Problem Solving - * [ ] Problem Solving - Fizz-Buzz Example - * [ ] Capstone Project -9. Built-in and Modules - * [ ] `math` module - * [ ] `json` module - * [ ] `random` module - * [ ] `datetime` module - * [ ] `pathlib` / `os` module - * [ ] `csv` module - * [ ] `sys` module -9. Third-party Modules - * [ ] Virtual Environments - * [ ] Using `pip` and `requirements.txt` - * [ ] Creating python package - `pyproject.toml` file - * [ ] ? Linting, Formatting, Type Checking (`ruff`, `mypy`) ? -14. Capstone Project 4 - * [ ] Clean Code Priciples - * [ ] Capstone Project - * [ ] Testing Your Code (`pytest`) - * [ ] Revisit Project 4 - * Develop a testing suite for the project -15. Object Oriented Programming - Part 1 - * [ ] Introduction to classes and instances - * [ ] Methods (instance, class, static) - * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -16. Capstone Project 5 - * [ ] Capstone Project -17. Object Oriented Programming - Part 2 - * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -18. Capstone Project 6 -10. Third-party Modules - * [ ] Virtual Environments - * [ ] Using `pip` and `requirements.txt` - * [ ] Creating python package - `pyproject.toml` file -11. Capstone Project 2 - * [ ] Clean Code Priciples - * [ ] Capstone Project -12. Object Oriented Programming - Part 1 - * [ ] Introduction to classes and instances - * [ ] Methods (instance, class, static) - * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -13. Capstone Project 3 - * [ ] Capstone Project -14. Object Oriented Programming - Part 2 - * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -15. Capstone Project 4 - * [ ] Capstone Project -======= -10. Third-party Modules -======= -9. Third-party Modules ->>>>>>> 71088b3 (Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson) - * [ ] Virtual Environments - * [ ] Using `pip` and `requirements.txt` - * [ ] Creating python package - `pyproject.toml` file -10. Capstone Project 2 - * [ ] Clean Code Priciples - * [ ] Capstone Project -11. Object Oriented Programming - Part 1 - * [ ] Introduction to classes and instances - * [ ] Methods (instance, class, static) - * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -12. Capstone Project 3 - * [ ] Capstone Project -13. Object Oriented Programming - Part 2 - * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -14. Capstone Project 4 - * [ ] Capstone Project ->>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) +7. Working on Projects, Solving bugs, Reading errors \ No newline at end of file diff --git a/scripts/roadmap/sync_discord.py b/scripts/roadmap/sync_discord.py index 85727a1..d4934d5 100644 --- a/scripts/roadmap/sync_discord.py +++ b/scripts/roadmap/sync_discord.py @@ -22,7 +22,10 @@ import os import re import sys +<<<<<<< HEAD import urllib.error +======= +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) import urllib.request ROADMAP_PATH = "ROADMAP.md" @@ -89,11 +92,16 @@ def build_embed(phases: list[Phase]) -> dict: def patch_message(webhook_url: str, message_id: str, embed: dict) -> None: url = f"{webhook_url}/messages/{message_id}" +<<<<<<< HEAD payload = json.dumps({"content": "", "embeds": [embed]}).encode("utf-8") +======= + payload = json.dumps({"embeds": [embed]}).encode("utf-8") +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) req = urllib.request.Request( url, data=payload, method="PATCH", +<<<<<<< HEAD headers={ "Content-Type": "application/json", "User-Agent": "ThePythonLedger-RoadmapSync (https://github.com/ThePythonLedger/Curriculum, 1.0)", @@ -110,6 +118,16 @@ def patch_message(webhook_url: str, message_id: str, embed: dict) -> None: body = e.read().decode("utf-8", errors="replace") print(f"HTTP {e.code} updating message {message_id}: {body}", file=sys.stderr) raise +======= + headers={"Content-Type": "application/json"}, + ) + with urllib.request.urlopen(req) as resp: + if resp.status not in (200, 204): + print( + f"Unexpected status {resp.status} updating message {message_id}", + file=sys.stderr, + ) +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) def main() -> None: diff --git a/scripts/roadmap/sync_roadmap.py b/scripts/roadmap/sync_roadmap.py index f784676..82bdf94 100644 --- a/scripts/roadmap/sync_roadmap.py +++ b/scripts/roadmap/sync_roadmap.py @@ -4,9 +4,15 @@ change) and updates the matching line in ROADMAP.md to one of three states: +<<<<<<< HEAD [ ] Lists — #34 not started [ ] 🚧 Lists — #34 👤 alice, bob in progress (assigned / open PR) [x] Lists — #34 done (merged / issue closed) +======= + [ ] Lists — #34 not started + [ ] 🚧 Lists — #34 in progress (assigned / open PR) + [x] Lists — #34 done (merged / issue closed) +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) GitHub's task-list rendering only recognizes [ ] and [x] as real, interactive checkboxes — anything else (like a bare [-]) is just @@ -14,10 +20,13 @@ strictly boolean (done / not done), and "in progress" is layered on as a 🚧 badge in the visible text instead of a third bracket state. +<<<<<<< HEAD While a lesson is in progress, the issue's assignees are listed at the end of the line after a 👤 marker (plain usernames, no @ mentions). The names are dropped again once the lesson is done or unassigned. +======= +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) This only touches roadmap lines that already reference an issue, e.g.: * [ ] Lists — #34 @@ -25,6 +34,7 @@ Lines with no "— #N" suffix are left alone — link an issue to a lesson by adding that suffix, and the automation picks it up from then on. """ +<<<<<<< HEAD import json import os import re @@ -36,21 +46,40 @@ # Internal state codes: " " = not started, "-" = in progress, "x" = done. # Only how they're RENDERED matters to GitHub's markdown. +======= + +import json +import os +import re + +ROADMAP_PATH = "ROADMAP.md" +WIP_BADGE = "🚧" + +# Internal state codes (unchanged from before): " " = not started, +# "-" = in progress, "x" = done. Only how they're RENDERED changes. +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) STATE_RENDER = { " ": {"check": " ", "badge": ""}, "-": {"check": " ", "badge": f"{WIP_BADGE} "}, "x": {"check": "x", "badge": ""}, } +<<<<<<< HEAD # Matches e.g. " * [ ] 🚧 Lists — #34 👤 alice" and captures the checkbox, # an optional WIP badge, and the issue number. `rest` is everything after # the issue number (including any assignee suffix, handled separately). +======= +# Matches e.g. " * [ ] 🚧 Lists — #34" and captures the checkbox, +# an optional WIP badge, and the issue number — everything else on +# the line is left untouched. +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) LINE_RE = re.compile( r"^(?P\s*\*\s*\[)(?P[ x])(?P\]\s*)" rf"(?P{WIP_BADGE}\s*)?" r"(?P.*?—\s*#)(?P\d+)(?P.*)$" ) +<<<<<<< HEAD # The assignee suffix always sits at the very end of the line. ASSIGNEE_SUFFIX_RE = re.compile(rf"\s+{ASSIGNEE_MARKER}\s+.*$") @@ -66,6 +95,8 @@ class Update(NamedTuple): # since a PR payload doesn't carry the linked issue's assignee list. assignees: list[str] | None = None +======= +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) def current_state(check: str, badge: str | None) -> str: if check == "x": @@ -73,6 +104,7 @@ def current_state(check: str, badge: str | None) -> str: return "-" if badge else " " +<<<<<<< HEAD def state_for_issue(issue: dict) -> str: if issue.get("state") == "closed": return "x" @@ -98,6 +130,31 @@ def updates_for_issue_event(event: dict) -> dict[int, Update]: def updates_for_pr_event(event: dict) -> dict[int, Update]: +======= +# Matches "Closes #12", "Fixes #34", "Resolves #7", etc. (repeatable, case-insensitive) +ISSUE_REF_RE = re.compile( + r"(?:clos(?:e[sd]?)|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)", re.IGNORECASE +) + + +def marker_for_issue_event(event: dict) -> dict[int, str]: + action = event["action"] + issue_number = event["issue"]["number"] + + if action == "assigned": + return {issue_number: "-"} + if action == "unassigned": + return {issue_number: " "} + if action == "closed": + return {issue_number: "x"} + if action == "reopened": + has_assignee = bool(event["issue"].get("assignees")) + return {issue_number: "-" if has_assignee else " "} + return {} + + +def marker_for_pr_event(event: dict) -> dict[int, str]: +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) action = event["action"] pr = event["pull_request"] body = pr.get("body") or "" @@ -106,6 +163,7 @@ def updates_for_pr_event(event: dict) -> dict[int, Update]: return {} if action in ("opened", "ready_for_review"): +<<<<<<< HEAD update = Update("-") elif action == "closed": update = Update("x") if pr.get("merged") else Update("-") @@ -113,6 +171,15 @@ def updates_for_pr_event(event: dict) -> dict[int, Update]: return {} return {n: update for n in issue_numbers} +======= + marker = "-" + elif action == "closed": + marker = "x" if pr.get("merged") else "-" + else: + return {} + + return {n: marker for n in issue_numbers} +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) def load_event() -> dict: @@ -120,11 +187,16 @@ def load_event() -> dict: return json.load(f) +<<<<<<< HEAD def compute_updates() -> dict[int, Update]: +======= +def compute_updates() -> dict[int, str]: +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) event_name = os.environ["GITHUB_EVENT_NAME"] event = load_event() if event_name == "issues": +<<<<<<< HEAD return updates_for_issue_event(event) if event_name in ("pull_request", "pull_request_target"): return updates_for_pr_event(event) @@ -142,15 +214,28 @@ def render_suffix(update: Update, existing_suffix: str) -> str: def apply_updates(updates: dict[int, Update]) -> bool: +======= + return marker_for_issue_event(event) + if event_name == "pull_request" or event_name == "pull_request_target": + return marker_for_pr_event(event) + return {} + + +def apply_updates(updates: dict[int, str]) -> bool: +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) with open(ROADMAP_PATH, encoding="utf-8") as f: lines = f.readlines() changed = False for i, line in enumerate(lines): +<<<<<<< HEAD stripped = line.rstrip("\r\n") eol = line[len(stripped):] m = LINE_RE.match(stripped) +======= + m = LINE_RE.match(line.rstrip("\n")) +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) if not m: continue @@ -158,6 +243,7 @@ def apply_updates(updates: dict[int, Update]) -> bool: if issue not in updates: continue +<<<<<<< HEAD update = updates[issue] old_state = current_state(m.group("check"), m.group("badge")) render = STATE_RENDER[update.state] @@ -179,6 +265,26 @@ def apply_updates(updates: dict[int, Update]) -> bool: lines[i] = new_line changed = True print(f"#{issue}: [{old_state}] -> [{update.state}]{suffix}") +======= + new_state = updates[issue] + old_state = current_state(m.group("check"), m.group("badge")) + if old_state == new_state: + continue + + render = STATE_RENDER[new_state] + lines[i] = ( + m.group("prefix") + + render["check"] + + m.group("mid") + + render["badge"] + + m.group("body") + + m.group("issue") + + m.group("rest") + + "\n" + ) + changed = True + print(f"#{issue}: [{old_state}] -> [{new_state}]") +>>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) if changed: with open(ROADMAP_PATH, "w", encoding="utf-8") as f: From c2f6021b81114ba3c0cc7b3985082b5c0046df0e Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 23:28:36 +0200 Subject: [PATCH 51/81] Added a reconcile step for manual triggering and scheduled at 04:00 AM --- .github/workflows/sync_roadmap_status.yml | 43 +++++++++++++++++++++++ ROADMAP.md | 11 ++++++ 2 files changed, 54 insertions(+) diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml index 122664a..da7f7e3 100644 --- a/.github/workflows/sync_roadmap_status.yml +++ b/.github/workflows/sync_roadmap_status.yml @@ -10,20 +10,27 @@ on: pull_request_target: types: [opened, ready_for_review, closed] <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 8c7939b (Added a reconcile step for manual triggering and scheduled at 04:00 AM) # Run reconcile.py on demand ("Run workflow" button) and once a day # as a safety net against any missed event (e.g. an issue closed # before its ROADMAP.md line had "— #N" linked to it yet). workflow_dispatch: {} schedule: - cron: "0 4 * * *" +<<<<<<< HEAD ======= >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +>>>>>>> 8c7939b (Added a reconcile step for manual triggering and scheduled at 04:00 AM) permissions: contents: write jobs: sync: +<<<<<<< HEAD <<<<<<< HEAD if: github.event_name == 'issues' || github.event_name == 'pull_request_target' runs-on: ubuntu-latest @@ -38,6 +45,9 @@ jobs: ref: main token: ${{ secrets.ROADMAP_PAT }} ======= +======= + if: github.event_name == 'issues' || github.event_name == 'pull_request_target' +>>>>>>> 8c7939b (Added a reconcile step for manual triggering and scheduled at 04:00 AM) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -63,6 +73,39 @@ jobs: commit_message: "chore: sync roadmap status [skip ci]" file_pattern: ROADMAP.md + - name: Sync Discord + if: steps.update.outputs.changed == 'true' + run: python scripts/roadmap/sync_discord.py + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} + + reconcile: + if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Reconcile ROADMAP.md with issue states + id: update + run: python scripts/roadmap/reconcile_roadmap.py + env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Commit ROADMAP.md + if: steps.update.outputs.changed == 'true' + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: reconcile roadmap status [skip ci]" + file_pattern: ROADMAP.md + - name: Sync Discord if: steps.update.outputs.changed == 'true' run: python scripts/roadmap/sync_discord.py diff --git a/ROADMAP.md b/ROADMAP.md index e51b7bc..3631c4c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -11,6 +11,7 @@ This may be subject to change. 1. Introduction * [x] How course works? * [x] Motivation and Mindset +<<<<<<< HEAD * [ ] Asking for help * [ ] Join the Community * [x] Computers and Programming Languages (CS Basics) @@ -19,6 +20,16 @@ This may be subject to change. * [x] Text Editor basics * [x] Command Line basics * [x] Python - What is it? REPL vs Scripts +======= + * [ ] Asking for Help — #32 + * [ ] Join the Community — #33 + * [x] Computer Science basics, Programming and Python +2. Prerequisites + * [x] Software Installation + * [x] Text and Code Editors + * [x] Command Line Basics + * [x] Python - REPL vs Scripts +>>>>>>> 8c7939b (Added a reconcile step for manual triggering and scheduled at 04:00 AM) 3. Git Basics * [x] Introduction to Git * [x] Setting up Git and Github From 5bef891492c58083e5d5351ea428c4bcbff3b54b Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:56:05 +0000 Subject: [PATCH 52/81] chore: reconcile roadmap status [skip ci] --- ROADMAP.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 3631c4c..604e49e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -11,6 +11,7 @@ This may be subject to change. 1. Introduction * [x] How course works? * [x] Motivation and Mindset +<<<<<<< HEAD <<<<<<< HEAD * [ ] Asking for help * [ ] Join the Community @@ -22,6 +23,9 @@ This may be subject to change. * [x] Python - What is it? REPL vs Scripts ======= * [ ] Asking for Help — #32 +======= + * [ ] 🚧 Asking for Help — #32 +>>>>>>> d188ac4 (chore: reconcile roadmap status [skip ci]) * [ ] Join the Community — #33 * [x] Computer Science basics, Programming and Python 2. Prerequisites @@ -39,6 +43,7 @@ This may be subject to change. * [x] Arithmetic and String Operations, Comparisons * [x] User Input and Conditionals * [x] Loops +<<<<<<< HEAD * [-] Data Structures * [-] List * [-] Tuple @@ -60,4 +65,69 @@ This may be subject to change. * [ ] Installation of third party libraries * [ ] Working with APIs * [ ] Project 3 - *probably: * weather app -7. Working on Projects, Solving bugs, Reading errors \ No newline at end of file +7. Working on Projects, Solving bugs, Reading errors +======= +5. Data Structures + * [ ] 🚧 Lists — #57 + * [ ] 🚧 Tuples — #58 + * [ ] 🚧 Sets — #59 + * [ ] 🚧 Dictionaries — #60 + * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 +6. Code Organization + * [ ] 🚧 Functions — #62 + * [ ] 🚧 Scope and Namespaces (LEGB rule) — #63 + * [ ] 🚧 Type Hints — #64 + * [ ] 🚧 Modules — #65 +7. Capstone Project 1 + * [ ] 🚧 Problem Solving — #66 + * [ ] 🚧 Problem Solving - Fizz-Buzz Example — #67 + * [ ] 🚧 Capstone Project - **Hangman game** — #68 +8. Errors, Debugging, I/O + * [ ] Understanding Errors and Error Handling + * [ ] `logging` module + * [ ] Debugging tehniques + * [ ] File Handling +9. Capstone Project 2 + * [ ] Git Workflow: Branches and Pull Requests + * [ ] Revisiting Project 1 (hangman game): + * Creating branch, adding features, merging back to `main` + * Loading *words* from external file + * Catching and logging errors + * [ ] Capstone Project +10. Intermediate Python + * [ ] Decorators + * [ ] Generators + * [ ] Context Managers +11. Capstone Project 3 + * [ ] Capstone Project +12. Built-in and Modules + * [ ] `math` module + * [ ] `json` module + * [ ] `random` module + * [ ] `datetime` module + * [ ] `pathlib` / `os` module + * [ ] `csv` module + * [ ] `sys` module + * [ ] `re` module +13. Third-party Modules + * [ ] Virtual Environments + * [ ] Using `pip` and `requirements.txt` + * [ ] Creating python package - `pyproject.toml` file + * [ ] ? Linting, Formatting, Type Checking (`ruff`, `mypy`) ? +14. Capstone Project 4 + * [ ] Clean Code Priciples + * [ ] Capstone Project + * [ ] Testing Your Code (`pytest`) + * [ ] Revisit Project 4 + * Develop a testing suite for the project +15. Object Oriented Programming - Part 1 + * [ ] Introduction to classes and instances + * [ ] Methods (instance, class, static) + * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) +16. Capstone Project 5 + * [ ] Capstone Project +17. Object Oriented Programming - Part 2 + * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) +18. Capstone Project 6 + * [ ] Capstone Project +>>>>>>> d188ac4 (chore: reconcile roadmap status [skip ci]) From ffc3539dfd636f40911240212d9e2873e18b41ec Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:57:39 +0000 Subject: [PATCH 53/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 604e49e..da5856d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -74,7 +74,7 @@ This may be subject to change. * [ ] 🚧 Dictionaries — #60 * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization - * [ ] 🚧 Functions — #62 + * [ ] Functions — #62 * [ ] 🚧 Scope and Namespaces (LEGB rule) — #63 * [ ] 🚧 Type Hints — #64 * [ ] 🚧 Modules — #65 From e2d340a1c329b7fe071f47fc230ef559b52598ed Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:58:10 +0000 Subject: [PATCH 54/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index da5856d..b86ca54 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -75,7 +75,7 @@ This may be subject to change. * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 6. Code Organization * [ ] Functions — #62 - * [ ] 🚧 Scope and Namespaces (LEGB rule) — #63 + * [ ] Scope and Namespaces (LEGB rule) — #63 * [ ] 🚧 Type Hints — #64 * [ ] 🚧 Modules — #65 7. Capstone Project 1 From dcfc66139ced96321c6ed3f16fc05258a9e4e2ac Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:58:22 +0000 Subject: [PATCH 55/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index b86ca54..3e3690e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -76,7 +76,7 @@ This may be subject to change. 6. Code Organization * [ ] Functions — #62 * [ ] Scope and Namespaces (LEGB rule) — #63 - * [ ] 🚧 Type Hints — #64 + * [ ] Type Hints — #64 * [ ] 🚧 Modules — #65 7. Capstone Project 1 * [ ] 🚧 Problem Solving — #66 From 6ee47f0d2dcd153aa48ba4e93b42bba6c170de66 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:00:49 +0000 Subject: [PATCH 56/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 3e3690e..5ae5e53 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -81,7 +81,7 @@ This may be subject to change. 7. Capstone Project 1 * [ ] 🚧 Problem Solving — #66 * [ ] 🚧 Problem Solving - Fizz-Buzz Example — #67 - * [ ] 🚧 Capstone Project - **Hangman game** — #68 + * [ ] Capstone Project - **Hangman game** — #68 8. Errors, Debugging, I/O * [ ] Understanding Errors and Error Handling * [ ] `logging` module From 29a8cc1535272eac7bf2ddc4c0be546214172245 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:00:57 +0000 Subject: [PATCH 57/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 5ae5e53..cad3dcd 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -80,7 +80,7 @@ This may be subject to change. * [ ] 🚧 Modules — #65 7. Capstone Project 1 * [ ] 🚧 Problem Solving — #66 - * [ ] 🚧 Problem Solving - Fizz-Buzz Example — #67 + * [ ] Problem Solving - Fizz-Buzz Example — #67 * [ ] Capstone Project - **Hangman game** — #68 8. Errors, Debugging, I/O * [ ] Understanding Errors and Error Handling From 3deb9a9c878ece46aea6b8eca61a5a200c520a96 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:01:01 +0000 Subject: [PATCH 58/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index cad3dcd..c16ffad 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -79,7 +79,7 @@ This may be subject to change. * [ ] Type Hints — #64 * [ ] 🚧 Modules — #65 7. Capstone Project 1 - * [ ] 🚧 Problem Solving — #66 + * [ ] Problem Solving — #66 * [ ] Problem Solving - Fizz-Buzz Example — #67 * [ ] Capstone Project - **Hangman game** — #68 8. Errors, Debugging, I/O From f068a2f0822a4d27a02ead691da18e6ce2d0a880 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:01:09 +0000 Subject: [PATCH 59/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index c16ffad..2d9b63e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -77,7 +77,7 @@ This may be subject to change. * [ ] Functions — #62 * [ ] Scope and Namespaces (LEGB rule) — #63 * [ ] Type Hints — #64 - * [ ] 🚧 Modules — #65 + * [ ] Modules — #65 7. Capstone Project 1 * [ ] Problem Solving — #66 * [ ] Problem Solving - Fizz-Buzz Example — #67 From 52bca14ca56cfe155864271388eb6ce6bfde9bfe Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 28 Sep 2026 00:08:45 +0000 Subject: [PATCH 60/81] chore: reconcile roadmap status [skip ci] --- ROADMAP.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 2d9b63e..9c23243 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,6 +12,7 @@ This may be subject to change. * [x] How course works? * [x] Motivation and Mindset <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD * [ ] Asking for help * [ ] Join the Community @@ -26,6 +27,9 @@ This may be subject to change. ======= * [ ] 🚧 Asking for Help — #32 >>>>>>> d188ac4 (chore: reconcile roadmap status [skip ci]) +======= + * [ ] 🚧 Asking for Help — #32 👤 tkcompani +>>>>>>> 3f081b9 (chore: reconcile roadmap status [skip ci]) * [ ] Join the Community — #33 * [x] Computer Science basics, Programming and Python 2. Prerequisites @@ -68,11 +72,11 @@ This may be subject to change. 7. Working on Projects, Solving bugs, Reading errors ======= 5. Data Structures - * [ ] 🚧 Lists — #57 - * [ ] 🚧 Tuples — #58 - * [ ] 🚧 Sets — #59 - * [ ] 🚧 Dictionaries — #60 - * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 + * [ ] 🚧 Lists — #57 👤 razorblade23 + * [ ] 🚧 Tuples — #58 👤 razorblade23 + * [ ] 🚧 Sets — #59 👤 razorblade23 + * [ ] 🚧 Dictionaries — #60 👤 razorblade23 + * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 👤 razorblade23 6. Code Organization * [ ] Functions — #62 * [ ] Scope and Namespaces (LEGB rule) — #63 From 3133b02f2b433571181282bb224474afafe09560 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Thu, 1 Oct 2026 05:51:56 +0000 Subject: [PATCH 61/81] chore: sync roadmap status [skip ci] --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 9c23243..662a1f5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -78,7 +78,7 @@ This may be subject to change. * [ ] 🚧 Dictionaries — #60 👤 razorblade23 * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 👤 razorblade23 6. Code Organization - * [ ] Functions — #62 + * [ ] 🚧 Functions — #62 👤 tajirdev * [ ] Scope and Namespaces (LEGB rule) — #63 * [ ] Type Hints — #64 * [ ] Modules — #65 From 73afb43a959d9503e57dce8a46a32017fcccddf1 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sat, 12 Sep 2026 09:33:50 +0200 Subject: [PATCH 62/81] Updated lists lessons and ROADMAPmd --- ROADMAP.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 662a1f5..b0d1061 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -10,6 +10,7 @@ This may be subject to change. ## Roadmap 1. Introduction * [x] How course works? +<<<<<<< HEAD * [x] Motivation and Mindset <<<<<<< HEAD <<<<<<< HEAD @@ -31,6 +32,11 @@ This may be subject to change. * [ ] 🚧 Asking for Help — #32 👤 tkcompani >>>>>>> 3f081b9 (chore: reconcile roadmap status [skip ci]) * [ ] Join the Community — #33 +======= + * [ ] Motivation and Mindset + * [ ] Asking for Help + * [x] Join the Community +>>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) * [x] Computer Science basics, Programming and Python 2. Prerequisites * [x] Software Installation @@ -72,6 +78,7 @@ This may be subject to change. 7. Working on Projects, Solving bugs, Reading errors ======= 5. Data Structures +<<<<<<< HEAD * [ ] 🚧 Lists — #57 👤 razorblade23 * [ ] 🚧 Tuples — #58 👤 razorblade23 * [ ] 🚧 Sets — #59 👤 razorblade23 @@ -105,6 +112,27 @@ This may be subject to change. 11. Capstone Project 3 * [ ] Capstone Project 12. Built-in and Modules +======= + * [x] Lists + * [x] Tuples + * [x] Sets + * [x] Dictionaries +6. Comprehensions + * [ ] List Coprehension + * [ ] Set Coprehension + * [ ] Dict Coprehension +7. Code Organization + * [ ] Functions + * [ ] Scope and Namespaces (LEGB rule) + * [ ] Understanding Errors and Error Handling + * [ ] File Handling + * [ ] Modules +8. Capstone Project 1 + * [ ] Problem Solving + * [ ] Problem Solving - Fizz-Buzz Example + * [ ] Capstone Project +9. Built-in and Modules +>>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) * [ ] `math` module * [ ] `json` module * [ ] `random` module @@ -112,6 +140,7 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module +<<<<<<< HEAD * [ ] `re` module 13. Third-party Modules * [ ] Virtual Environments @@ -134,4 +163,22 @@ This may be subject to change. * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) 18. Capstone Project 6 * [ ] Capstone Project ->>>>>>> d188ac4 (chore: reconcile roadmap status [skip ci]) +======= +10. Third-party Modules + * [ ] Virtual Environments + * [ ] Using `pip` and `requirements.txt` + * [ ] Creating python package - `pyproject.toml` file +11. Capstone Project 2 + * [ ] Clean Code Priciples + * [ ] Capstone Project +12. Object Oriented Programming - Part 1 + * [ ] Introduction to classes and instances + * [ ] Methods (instance, class, static) + * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) +13. Capstone Project 3 + * [ ] Capstone Project +14. Object Oriented Programming - Part 2 + * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) +15. Capstone Project 4 + * [ ] Capstone Project +>>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) From 0fd56944e8332404ef9a7a55bca014b94ba92cdf Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 13 Sep 2026 16:57:49 +0200 Subject: [PATCH 63/81] Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson --- ROADMAP.md | 89 ++++++++---------------------------------------------- 1 file changed, 13 insertions(+), 76 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index b0d1061..e09251c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -78,61 +78,22 @@ This may be subject to change. 7. Working on Projects, Solving bugs, Reading errors ======= 5. Data Structures -<<<<<<< HEAD - * [ ] 🚧 Lists — #57 👤 razorblade23 - * [ ] 🚧 Tuples — #58 👤 razorblade23 - * [ ] 🚧 Sets — #59 👤 razorblade23 - * [ ] 🚧 Dictionaries — #60 👤 razorblade23 - * [ ] 🚧 Coprehensions (`list`, `dict` `set`) — #61 👤 razorblade23 + * [x] Lists (WIP) + * [x] Tuples (WIP) + * [x] Sets (WIP) + * [x] Dictionaries (WIP) + * [x] Coprehensions (`list`, `dict` `set`) (WIP) 6. Code Organization - * [ ] 🚧 Functions — #62 👤 tajirdev - * [ ] Scope and Namespaces (LEGB rule) — #63 - * [ ] Type Hints — #64 - * [ ] Modules — #65 -7. Capstone Project 1 - * [ ] Problem Solving — #66 - * [ ] Problem Solving - Fizz-Buzz Example — #67 - * [ ] Capstone Project - **Hangman game** — #68 -8. Errors, Debugging, I/O - * [ ] Understanding Errors and Error Handling - * [ ] `logging` module - * [ ] Debugging tehniques - * [ ] File Handling -9. Capstone Project 2 - * [ ] Git Workflow: Branches and Pull Requests - * [ ] Revisiting Project 1 (hangman game): - * Creating branch, adding features, merging back to `main` - * Loading *words* from external file - * Catching and logging errors - * [ ] Capstone Project -10. Intermediate Python - * [ ] Decorators - * [ ] Generators - * [ ] Context Managers -11. Capstone Project 3 - * [ ] Capstone Project -12. Built-in and Modules -======= - * [x] Lists - * [x] Tuples - * [x] Sets - * [x] Dictionaries -6. Comprehensions - * [ ] List Coprehension - * [ ] Set Coprehension - * [ ] Dict Coprehension -7. Code Organization * [ ] Functions * [ ] Scope and Namespaces (LEGB rule) * [ ] Understanding Errors and Error Handling * [ ] File Handling * [ ] Modules -8. Capstone Project 1 +7. Capstone Project 1 * [ ] Problem Solving * [ ] Problem Solving - Fizz-Buzz Example * [ ] Capstone Project -9. Built-in and Modules ->>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) +8. Built-in and Modules * [ ] `math` module * [ ] `json` module * [ ] `random` module @@ -140,45 +101,21 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module -<<<<<<< HEAD - * [ ] `re` module -13. Third-party Modules - * [ ] Virtual Environments - * [ ] Using `pip` and `requirements.txt` - * [ ] Creating python package - `pyproject.toml` file - * [ ] ? Linting, Formatting, Type Checking (`ruff`, `mypy`) ? -14. Capstone Project 4 - * [ ] Clean Code Priciples - * [ ] Capstone Project - * [ ] Testing Your Code (`pytest`) - * [ ] Revisit Project 4 - * Develop a testing suite for the project -15. Object Oriented Programming - Part 1 - * [ ] Introduction to classes and instances - * [ ] Methods (instance, class, static) - * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -16. Capstone Project 5 - * [ ] Capstone Project -17. Object Oriented Programming - Part 2 - * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -18. Capstone Project 6 - * [ ] Capstone Project -======= -10. Third-party Modules +9. Third-party Modules * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file -11. Capstone Project 2 +10. Capstone Project 2 * [ ] Clean Code Priciples * [ ] Capstone Project -12. Object Oriented Programming - Part 1 +11. Object Oriented Programming - Part 1 * [ ] Introduction to classes and instances * [ ] Methods (instance, class, static) * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -13. Capstone Project 3 +12. Capstone Project 3 * [ ] Capstone Project -14. Object Oriented Programming - Part 2 +13. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -15. Capstone Project 4 +14. Capstone Project 4 * [ ] Capstone Project >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) From 34ef0d6a9d2f3a5d03d3c002a4c23c8c14189740 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 16 Sep 2026 16:21:03 +0200 Subject: [PATCH 64/81] Couple of changes to lesson and better ROADMAP.md --- ROADMAP.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index e09251c..517318b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -34,7 +34,7 @@ This may be subject to change. * [ ] Join the Community — #33 ======= * [ ] Motivation and Mindset - * [ ] Asking for Help + * [ ] Asking for Help (WIP) * [x] Join the Community >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) * [x] Computer Science basics, Programming and Python @@ -78,11 +78,11 @@ This may be subject to change. 7. Working on Projects, Solving bugs, Reading errors ======= 5. Data Structures - * [x] Lists (WIP) - * [x] Tuples (WIP) - * [x] Sets (WIP) - * [x] Dictionaries (WIP) - * [x] Coprehensions (`list`, `dict` `set`) (WIP) + * [ ] Lists (WIP) + * [ ] Tuples (WIP) + * [ ] Sets (WIP) + * [ ] Dictionaries (WIP) + * [ ] Coprehensions (`list`, `dict` `set`) (WIP) 6. Code Organization * [ ] Functions * [ ] Scope and Namespaces (LEGB rule) From b8b4d983af2a6aad509941f0138c8cbe96864220 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 16 Sep 2026 22:56:24 +0200 Subject: [PATCH 65/81] Updated roadmap with missing topics --- ROADMAP.md | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 517318b..7ad7be2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -86,14 +86,31 @@ This may be subject to change. 6. Code Organization * [ ] Functions * [ ] Scope and Namespaces (LEGB rule) - * [ ] Understanding Errors and Error Handling - * [ ] File Handling + * [ ] Type Hints * [ ] Modules 7. Capstone Project 1 * [ ] Problem Solving * [ ] Problem Solving - Fizz-Buzz Example + * [ ] Capstone Project - **Hangman game** +8. Errors, Debugging, I/O + * [ ] Understanding Errors and Error Handling + * [ ] `logging` module + * [ ] Debugging tehniques + * [ ] File Handling +9. Capstone Project 2 + * [ ] Git Workflow: Branches and Pull Requests + * [ ] Revisiting Project 1 (hangman game): + * Creating branch, adding features, merging back to `main` + * Loading *words* from external file + * Catching and logging errors * [ ] Capstone Project -8. Built-in and Modules +10. Intermediate Python + * [ ] Decorators + * [ ] Generators + * [ ] Context Managers +11. Capstone Project 3 + * [ ] Capstone Project +12. Built-in and Modules * [ ] `math` module * [ ] `json` module * [ ] `random` module @@ -101,21 +118,26 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module -9. Third-party Modules + * [ ] `re` module +13. Third-party Modules * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file -10. Capstone Project 2 + * [ ] ? Linting, Formatting, Type Checking (`ruff`, `mypy`) ? +14. Capstone Project 4 * [ ] Clean Code Priciples * [ ] Capstone Project -11. Object Oriented Programming - Part 1 + * [ ] Testing Your Code (`pytest`) + * [ ] Revisit Project 4 + * Develop a testing suite for the project +15. Object Oriented Programming - Part 1 * [ ] Introduction to classes and instances * [ ] Methods (instance, class, static) * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -12. Capstone Project 3 +16. Capstone Project 5 * [ ] Capstone Project -13. Object Oriented Programming - Part 2 +17. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -14. Capstone Project 4 +18. Capstone Project 6 * [ ] Capstone Project >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) From 6881bd9ddccf5ff772dce01a63654df4e99fd0c0 Mon Sep 17 00:00:00 2001 From: amotech Date: Mon, 28 Sep 2026 15:41:50 +0000 Subject: [PATCH 66/81] test3 --- ROADMAP.md | 163 +++++++++++++----- .../01-introduction/03-asking-for-help.md | 41 +---- 2 files changed, 122 insertions(+), 82 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 7ad7be2..2667f8c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -5,32 +5,14 @@ This may be subject to change. `[ ]` - no work has been done `[ ] 🚧` - work in progress (assigned / open PR) `[x]` - lesson completed -`👤 name` - who is working on issue ## Roadmap 1. Introduction * [x] How course works? <<<<<<< HEAD * [x] Motivation and Mindset -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - * [ ] Asking for help - * [ ] Join the Community - * [x] Computers and Programming Languages (CS Basics) -2. Prerequisites - * [x] Installation of required software - * [x] Text Editor basics - * [x] Command Line basics - * [x] Python - What is it? REPL vs Scripts -======= + * [ ] Asking for Help (WIP) — #32 * [ ] Asking for Help — #32 -======= - * [ ] 🚧 Asking for Help — #32 ->>>>>>> d188ac4 (chore: reconcile roadmap status [skip ci]) -======= - * [ ] 🚧 Asking for Help — #32 👤 tkcompani ->>>>>>> 3f081b9 (chore: reconcile roadmap status [skip ci]) * [ ] Join the Community — #33 ======= * [ ] Motivation and Mindset @@ -78,39 +60,96 @@ This may be subject to change. 7. Working on Projects, Solving bugs, Reading errors ======= 5. Data Structures - * [ ] Lists (WIP) - * [ ] Tuples (WIP) - * [ ] Sets (WIP) - * [ ] Dictionaries (WIP) - * [ ] Coprehensions (`list`, `dict` `set`) (WIP) + * [ ] Lists — #57 + * [ ] Tuples — #58 + * [ ] Sets — #59 + * [ ] Dictionaries — #60 + * [ ] Coprehensions (`list`, `dict` `set`) — #61 + * [x] Lists (WIP) + * [x] Tuples (WIP) + * [x] Sets (WIP) + * [x] Dictionaries (WIP) + * [x] Coprehensions (`list`, `dict` `set`) (WIP) 6. Code Organization - * [ ] Functions - * [ ] Scope and Namespaces (LEGB rule) - * [ ] Type Hints - * [ ] Modules + * [ ] Functions — #62 + * [ ] Scope and Namespaces (LEGB rule) — #63 + * [ ] 🚧 Type Hints — #64 + * [ ] 🚧 Modules — #65 7. Capstone Project 1 * [ ] Problem Solving * [ ] Problem Solving - Fizz-Buzz Example * [ ] Capstone Project - **Hangman game** 8. Errors, Debugging, I/O + * [ ] Functions + * [ ] Scope and Namespaces (LEGB rule) * [ ] Understanding Errors and Error Handling - * [ ] `logging` module - * [ ] Debugging tehniques * [ ] File Handling -9. Capstone Project 2 - * [ ] Git Workflow: Branches and Pull Requests - * [ ] Revisiting Project 1 (hangman game): - * Creating branch, adding features, merging back to `main` - * Loading *words* from external file - * Catching and logging errors - * [ ] Capstone Project -10. Intermediate Python - * [ ] Decorators - * [ ] Generators - * [ ] Context Managers -11. Capstone Project 3 + * [ ] Modules +7. Capstone Project 1 + * [ ] Problem Solving + * [ ] Problem Solving - Fizz-Buzz Example * [ ] Capstone Project 12. Built-in and Modules + * [-] Data Structures + * [-] List + * [-] Tuple + * [-] Set + * [-] Dictionary + * [ ] Functions + * [ ] Project 1 +5. Modules, Working with Files and Error Handling + * [ ] Working with multiple files (`__init.py__`, directory structure, etc...) + * [ ] Opening, Closing and Manipulating files + * [ ] Error Handling (`try-except-else-finally`) + * [ ] Custom Exceptions + * [ ] Defensive Coding patterns + * [ ] Working with structured data (`json`, `csv`, etc...) + * [ ] Project 2 +6. OOP, Virtual Environments and third party libraries, Working with APIs + * [ ] Classes and OOP + * [ ] Usage and setup of virtual environments + * [ ] Installation of third party libraries + * [ ] Working with APIs + * [ ] Project 3 - *probably: * weather app +7. Working on Projects, Solving bugs, Reading errors + * [ ] Motivation and Mindset + * [ ] Asking for Help (WIP) + * [x] Join the Community + * [x] Computer Science basics, Programming and Python +2. Prerequisites + * [x] Software Installation + * [x] Text and Code Editors + * [x] Command Line Basics + * [x] Python - REPL vs Scripts +3. Git Basics + * [x] Introduction to Git + * [x] Setting up Git and Github + * [x] Git Basics +4. Foundations + * [x] Output, Variables, Core Datatypes + * [x] Arithmetic and String Operations, Comparisons + * [x] User Input and Conditionals + * [x] Loops +5. Data Structures + * [x] Lists + * [x] Tuples + * [x] Sets + * [x] Dictionaries +6. Comprehensions + * [ ] List Coprehension + * [ ] Set Coprehension + * [ ] Dict Coprehension +7. Code Organization + * [ ] Functions + * [ ] Scope and Namespaces (LEGB rule) + * [ ] Understanding Errors and Error Handling + * [ ] File Handling + * [ ] Modules +8. Capstone Project 1 + * [ ] Problem Solving + * [ ] Problem Solving - Fizz-Buzz Example + * [ ] Capstone Project +9. Built-in and Modules * [ ] `math` module * [ ] `json` module * [ ] `random` module @@ -118,8 +157,7 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module - * [ ] `re` module -13. Third-party Modules +9. Third-party Modules * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file @@ -139,5 +177,42 @@ This may be subject to change. 17. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) 18. Capstone Project 6 +10. Third-party Modules + * [ ] Virtual Environments + * [ ] Using `pip` and `requirements.txt` + * [ ] Creating python package - `pyproject.toml` file +11. Capstone Project 2 + * [ ] Clean Code Priciples + * [ ] Capstone Project +12. Object Oriented Programming - Part 1 + * [ ] Introduction to classes and instances + * [ ] Methods (instance, class, static) + * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) +13. Capstone Project 3 + * [ ] Capstone Project +14. Object Oriented Programming - Part 2 + * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) +15. Capstone Project 4 + * [ ] Capstone Project +======= +10. Third-party Modules +======= +9. Third-party Modules +>>>>>>> 71088b3 (Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson) + * [ ] Virtual Environments + * [ ] Using `pip` and `requirements.txt` + * [ ] Creating python package - `pyproject.toml` file +10. Capstone Project 2 + * [ ] Clean Code Priciples + * [ ] Capstone Project +11. Object Oriented Programming - Part 1 + * [ ] Introduction to classes and instances + * [ ] Methods (instance, class, static) + * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) +12. Capstone Project 3 + * [ ] Capstone Project +13. Object Oriented Programming - Part 2 + * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) +14. Capstone Project 4 * [ ] Capstone Project >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index 7e4d9b8..4c9f46f 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -62,42 +62,7 @@ Steps to format your code: ### 4. What to Expect Next ➡ Once you have submitted your help request, sit down tight and the appropriate help will be sent straight to you. -If unfortunately the help response delays or never comes, use the next approach which is _Who To Ask_. +## Introduction +This lesson is intended to help you become good in seeking for help - -## Who to Ask for Help 🧔🏻❔ -subs: -* Ask yourself -* Ask someone with experience -* Ask a trusted community -* Ask an Ai agent - -### 1. Ask Yourself Before Anyone -You may say, why myself, i don't know?—Ofcourse you know all the answers to your own questions most of the times. **Ask yourself why, why did the error come; Ask yourself how, how did the error come; and Ask yourself what, what brought up a particular error** :(. You are not actually finding the correct solution to the cause of the error with these questions overnight (as if it was a magic :)), **but** what you are doing is you are training your thinking, which may help you think creatively gradually—to solve future problems. "Problem solving requires a creative and effective thinking"—Baldwin.J,. college success(2021). - -After you have had your answers to those three question, store them safely as we will learn how they might become useful later in this lesson. - -### 2. Ask Someone with Experience -Why ask someone with experience?—An experienced programmer, specifically python programmer, knows how to solve or debug almost every bug or error respectively. Therefore asking an experienced person means there is a higher probability you will get a solution to an/a error/bug. - -Now let see how your answers at the _ask yourself_ sub gets useful here. Compare your answers obtained at the _ask yourself_ sub to the ones you obtained from the experienced programmer and **Ask youself one more time—what did i missed?**—Keep this particular answer to yourself (treat it as important), it might help you in your future decisions when debugging other or similar errors later on. - -### 3. Ask a Trusted Community -Though there isn't a full guarantee that a community will contain only experienced programmers,—That is there would be beginners, intermediates and experts—but there are people with at least an experience if not much, these people might have already at least solved a bug which you just met, and could share with you how they handled it—which might be a fantastic approach you could learn also. - -Therefore asking verified communities like the stackoverflow, github, telegram groups, reddit, discord and others i could'nt mention—though one should proceed this with caution—is a must once you are learning the python or any other programming langauge. - -### 4. Ask an AI Agent -AI tools or agents are a smart way to debug errors faster, but the question is—Does the AI agent know the best approch to avoid future code breaks? - -This does not neccessarily mean using AI assistance for debugging errors is bad. But for best decision sake; That is if you know enough or understand how to select the best approach out of the many provided by the AI model, then you are encouraged to proceed with this approach—the advice is simple, that is use AI to recall the best solutions you already know quickly and not to decide the best solutions for you. - -This really counts in a serious project or even in the real world practices, but it is also a good thing to keep it in practice now—even if you are learning. - - -## Where to Ask for Help -- _work in progress_ - - - -[ **_WORK IN PROGRESS_** ] +## Work in progress From 70a3b2605c3b826125137c0bafb539bebd7be8f8 Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 22:51:49 +0200 Subject: [PATCH 67/81] Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow. --- .github/workflows/sync_roadmap_status.yml | 21 ++++ scripts/roadmap/sync_discord.py | 15 +++ scripts/roadmap/sync_roadmap.py | 119 ++++++++++++++++++---- 3 files changed, 135 insertions(+), 20 deletions(-) diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml index da7f7e3..c272604 100644 --- a/.github/workflows/sync_roadmap_status.yml +++ b/.github/workflows/sync_roadmap_status.yml @@ -11,8 +11,11 @@ on: types: [opened, ready_for_review, closed] <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 8c7939b (Added a reconcile step for manual triggering and scheduled at 04:00 AM) +======= +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) # Run reconcile.py on demand ("Run workflow" button) and once a day # as a safety net against any missed event (e.g. an issue closed # before its ROADMAP.md line had "— #N" linked to it yet). @@ -20,10 +23,15 @@ on: schedule: - cron: "0 4 * * *" <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) ======= >>>>>>> 8c7939b (Added a reconcile step for manual triggering and scheduled at 04:00 AM) +======= +======= +>>>>>>> 2bfe0cf (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) permissions: contents: write @@ -32,6 +40,9 @@ jobs: sync: <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) if: github.event_name == 'issues' || github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: @@ -45,15 +56,22 @@ jobs: ref: main token: ${{ secrets.ROADMAP_PAT }} ======= +<<<<<<< HEAD ======= if: github.event_name == 'issues' || github.event_name == 'pull_request_target' >>>>>>> 8c7939b (Added a reconcile step for manual triggering and scheduled at 04:00 AM) +======= +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: ref: main +<<<<<<< HEAD >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +>>>>>>> 2bfe0cf (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) - uses: actions/setup-python@v5 with: @@ -78,6 +96,7 @@ jobs: run: python scripts/roadmap/sync_discord.py env: DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} +<<<<<<< HEAD DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} reconcile: @@ -111,4 +130,6 @@ jobs: run: python scripts/roadmap/sync_discord.py env: DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} +======= +>>>>>>> 2bfe0cf (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} \ No newline at end of file diff --git a/scripts/roadmap/sync_discord.py b/scripts/roadmap/sync_discord.py index d4934d5..dc8dccc 100644 --- a/scripts/roadmap/sync_discord.py +++ b/scripts/roadmap/sync_discord.py @@ -23,9 +23,12 @@ import re import sys <<<<<<< HEAD +<<<<<<< HEAD import urllib.error ======= >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) import urllib.request ROADMAP_PATH = "ROADMAP.md" @@ -92,15 +95,20 @@ def build_embed(phases: list[Phase]) -> dict: def patch_message(webhook_url: str, message_id: str, embed: dict) -> None: url = f"{webhook_url}/messages/{message_id}" +<<<<<<< HEAD <<<<<<< HEAD payload = json.dumps({"content": "", "embeds": [embed]}).encode("utf-8") ======= payload = json.dumps({"embeds": [embed]}).encode("utf-8") >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= + payload = json.dumps({"embeds": [embed]}).encode("utf-8") +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) req = urllib.request.Request( url, data=payload, method="PATCH", +<<<<<<< HEAD <<<<<<< HEAD headers={ "Content-Type": "application/json", @@ -121,13 +129,20 @@ def patch_message(webhook_url: str, message_id: str, embed: dict) -> None: ======= headers={"Content-Type": "application/json"}, ) +======= + headers={"Content-Type": "application/json"}, + ) +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) with urllib.request.urlopen(req) as resp: if resp.status not in (200, 204): print( f"Unexpected status {resp.status} updating message {message_id}", file=sys.stderr, ) +<<<<<<< HEAD >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) def main() -> None: diff --git a/scripts/roadmap/sync_roadmap.py b/scripts/roadmap/sync_roadmap.py index 82bdf94..68a2924 100644 --- a/scripts/roadmap/sync_roadmap.py +++ b/scripts/roadmap/sync_roadmap.py @@ -4,6 +4,7 @@ change) and updates the matching line in ROADMAP.md to one of three states: +<<<<<<< HEAD <<<<<<< HEAD [ ] Lists — #34 not started [ ] 🚧 Lists — #34 👤 alice, bob in progress (assigned / open PR) @@ -13,6 +14,11 @@ [ ] 🚧 Lists — #34 in progress (assigned / open PR) [x] Lists — #34 done (merged / issue closed) >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= + [ ] Lists — #34 not started + [ ] 🚧 Lists — #34 in progress (assigned / open PR) + [x] Lists — #34 done (merged / issue closed) +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) GitHub's task-list rendering only recognizes [ ] and [x] as real, interactive checkboxes — anything else (like a bare [-]) is just @@ -20,6 +26,7 @@ strictly boolean (done / not done), and "in progress" is layered on as a 🚧 badge in the visible text instead of a third bracket state. +<<<<<<< HEAD <<<<<<< HEAD While a lesson is in progress, the issue's assignees are listed at the end of the line after a 👤 marker (plain usernames, no @ mentions). @@ -27,6 +34,8 @@ ======= >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) This only touches roadmap lines that already reference an issue, e.g.: * [ ] Lists — #34 @@ -35,15 +44,18 @@ by adding that suffix, and the automation picks it up from then on. """ <<<<<<< HEAD +<<<<<<< HEAD +======= + +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) import json import os import re -from typing import NamedTuple ROADMAP_PATH = "ROADMAP.md" WIP_BADGE = "🚧" -ASSIGNEE_MARKER = "👤" +<<<<<<< HEAD # Internal state codes: " " = not started, "-" = in progress, "x" = done. # Only how they're RENDERED matters to GitHub's markdown. ======= @@ -58,12 +70,17 @@ # Internal state codes (unchanged from before): " " = not started, # "-" = in progress, "x" = done. Only how they're RENDERED changes. >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +# Internal state codes (unchanged from before): " " = not started, +# "-" = in progress, "x" = done. Only how they're RENDERED changes. +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) STATE_RENDER = { " ": {"check": " ", "badge": ""}, "-": {"check": " ", "badge": f"{WIP_BADGE} "}, "x": {"check": "x", "badge": ""}, } +<<<<<<< HEAD <<<<<<< HEAD # Matches e.g. " * [ ] 🚧 Lists — #34 👤 alice" and captures the checkbox, # an optional WIP badge, and the issue number. `rest` is everything after @@ -73,12 +90,18 @@ # an optional WIP badge, and the issue number — everything else on # the line is left untouched. >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +# Matches e.g. " * [ ] 🚧 Lists — #34" and captures the checkbox, +# an optional WIP badge, and the issue number — everything else on +# the line is left untouched. +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) LINE_RE = re.compile( r"^(?P\s*\*\s*\[)(?P[ x])(?P\]\s*)" rf"(?P{WIP_BADGE}\s*)?" r"(?P.*?—\s*#)(?P\d+)(?P.*)$" ) +<<<<<<< HEAD <<<<<<< HEAD # The assignee suffix always sits at the very end of the line. ASSIGNEE_SUFFIX_RE = re.compile(rf"\s+{ASSIGNEE_MARKER}\s+.*$") @@ -97,6 +120,8 @@ class Update(NamedTuple): ======= >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) def current_state(check: str, badge: str | None) -> str: if check == "x": @@ -104,17 +129,37 @@ def current_state(check: str, badge: str | None) -> str: return "-" if badge else " " +<<<<<<< HEAD <<<<<<< HEAD def state_for_issue(issue: dict) -> str: if issue.get("state") == "closed": return "x" return "-" if issue.get("assignees") else " " +======= +# Matches "Closes #12", "Fixes #34", "Resolves #7", etc. (repeatable, case-insensitive) +ISSUE_REF_RE = re.compile( + r"(?:clos(?:e[sd]?)|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)", re.IGNORECASE +) +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) -def assignee_logins(issue: dict) -> list[str]: - return [a["login"] for a in issue.get("assignees") or []] +def marker_for_issue_event(event: dict) -> dict[int, str]: + action = event["action"] + issue_number = event["issue"]["number"] + + if action == "assigned": + return {issue_number: "-"} + if action == "unassigned": + return {issue_number: " "} + if action == "closed": + return {issue_number: "x"} + if action == "reopened": + has_assignee = bool(event["issue"].get("assignees")) + return {issue_number: "-" if has_assignee else " "} + return {} +<<<<<<< HEAD def update_from_issue(issue: dict) -> Update: """Works for both webhook payloads and REST API issue objects.""" return Update(state_for_issue(issue), assignee_logins(issue)) @@ -155,6 +200,9 @@ def marker_for_issue_event(event: dict) -> dict[int, str]: def marker_for_pr_event(event: dict) -> dict[int, str]: >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +def marker_for_pr_event(event: dict) -> dict[int, str]: +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) action = event["action"] pr = event["pull_request"] body = pr.get("body") or "" @@ -163,13 +211,18 @@ def marker_for_pr_event(event: dict) -> dict[int, str]: return {} if action in ("opened", "ready_for_review"): +<<<<<<< HEAD <<<<<<< HEAD update = Update("-") +======= + marker = "-" +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) elif action == "closed": - update = Update("x") if pr.get("merged") else Update("-") + marker = "x" if pr.get("merged") else "-" else: return {} +<<<<<<< HEAD return {n: update for n in issue_numbers} ======= marker = "-" @@ -180,6 +233,9 @@ def marker_for_pr_event(event: dict) -> dict[int, str]: return {n: marker for n in issue_numbers} >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= + return {n: marker for n in issue_numbers} +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) def load_event() -> dict: @@ -187,15 +243,20 @@ def load_event() -> dict: return json.load(f) +<<<<<<< HEAD <<<<<<< HEAD def compute_updates() -> dict[int, Update]: ======= def compute_updates() -> dict[int, str]: >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +def compute_updates() -> dict[int, str]: +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) event_name = os.environ["GITHUB_EVENT_NAME"] event = load_event() if event_name == "issues": +<<<<<<< HEAD <<<<<<< HEAD return updates_for_issue_event(event) if event_name in ("pull_request", "pull_request_target"): @@ -223,11 +284,21 @@ def apply_updates(updates: dict[int, Update]) -> bool: def apply_updates(updates: dict[int, str]) -> bool: >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= + return marker_for_issue_event(event) + if event_name == "pull_request" or event_name == "pull_request_target": + return marker_for_pr_event(event) + return {} + + +def apply_updates(updates: dict[int, str]) -> bool: +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) with open(ROADMAP_PATH, encoding="utf-8") as f: lines = f.readlines() changed = False for i, line in enumerate(lines): +<<<<<<< HEAD <<<<<<< HEAD stripped = line.rstrip("\r\n") eol = line[len(stripped):] @@ -236,6 +307,9 @@ def apply_updates(updates: dict[int, str]) -> bool: ======= m = LINE_RE.match(line.rstrip("\n")) >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= + m = LINE_RE.match(line.rstrip("\n")) +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) if not m: continue @@ -243,27 +317,29 @@ def apply_updates(updates: dict[int, str]) -> bool: if issue not in updates: continue +<<<<<<< HEAD <<<<<<< HEAD update = updates[issue] +======= + new_state = updates[issue] +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) old_state = current_state(m.group("check"), m.group("badge")) - render = STATE_RENDER[update.state] - - rest = m.group("rest") - existing = ASSIGNEE_SUFFIX_RE.search(rest) - rest_base = ASSIGNEE_SUFFIX_RE.sub("", rest) - suffix = render_suffix(update, existing.group(0) if existing else "") - if suffix: - rest_base = rest_base.rstrip() # no double space before the 👤 - - new_line = ( - m.group("prefix") + render["check"] + m.group("mid") + render["badge"] - + m.group("body") + m.group("issue") + rest_base + suffix + eol - ) - if new_line == line: + if old_state == new_state: continue - lines[i] = new_line + render = STATE_RENDER[new_state] + lines[i] = ( + m.group("prefix") + + render["check"] + + m.group("mid") + + render["badge"] + + m.group("body") + + m.group("issue") + + m.group("rest") + + "\n" + ) changed = True +<<<<<<< HEAD print(f"#{issue}: [{old_state}] -> [{update.state}]{suffix}") ======= new_state = updates[issue] @@ -285,6 +361,9 @@ def apply_updates(updates: dict[int, str]) -> bool: changed = True print(f"#{issue}: [{old_state}] -> [{new_state}]") >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= + print(f"#{issue}: [{old_state}] -> [{new_state}]") +>>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) if changed: with open(ROADMAP_PATH, "w", encoding="utf-8") as f: From e6d6ebd27d6ce4656067c451c5d8a041b42276e1 Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 23:28:36 +0200 Subject: [PATCH 68/81] Added a reconcile step for manual triggering and scheduled at 04:00 AM --- .github/workflows/sync_roadmap_status.yml | 78 +++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml index c272604..2e4dc49 100644 --- a/.github/workflows/sync_roadmap_status.yml +++ b/.github/workflows/sync_roadmap_status.yml @@ -12,10 +12,13 @@ on: <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 8c7939b (Added a reconcile step for manual triggering and scheduled at 04:00 AM) ======= >>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +>>>>>>> b74705e (Added a reconcile step for manual triggering and scheduled at 04:00 AM) # Run reconcile.py on demand ("Run workflow" button) and once a day # as a safety net against any missed event (e.g. an issue closed # before its ROADMAP.md line had "— #N" linked to it yet). @@ -24,6 +27,7 @@ on: - cron: "0 4 * * *" <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 78c3371 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) ======= @@ -32,6 +36,8 @@ on: ======= >>>>>>> 2bfe0cf (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) >>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) +======= +>>>>>>> b74705e (Added a reconcile step for manual triggering and scheduled at 04:00 AM) permissions: contents: write @@ -41,6 +47,7 @@ jobs: <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) if: github.event_name == 'issues' || github.event_name == 'pull_request_target' @@ -64,6 +71,11 @@ jobs: >>>>>>> c65e0c6 (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) runs-on: ubuntu-latest steps: +======= + if: github.event_name == 'issues' || github.event_name == 'pull_request_target' + runs-on: ubuntu-latest + steps: +>>>>>>> b74705e (Added a reconcile step for manual triggering and scheduled at 04:00 AM) - uses: actions/checkout@v4 with: ref: main @@ -96,6 +108,72 @@ jobs: run: python scripts/roadmap/sync_discord.py env: DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} + + reconcile: + if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Reconcile ROADMAP.md with issue states + id: update + run: python scripts/roadmap/reconcile_roadmap.py + env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Commit ROADMAP.md + if: steps.update.outputs.changed == 'true' + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: reconcile roadmap status [skip ci]" + file_pattern: ROADMAP.md + + - name: Sync Discord + if: steps.update.outputs.changed == 'true' + run: python scripts/roadmap/sync_discord.py + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} + + reconcile: + if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Reconcile ROADMAP.md with issue states + id: update + run: python scripts/roadmap/reconcile_roadmap.py + env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Commit ROADMAP.md + if: steps.update.outputs.changed == 'true' + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: reconcile roadmap status [skip ci]" + file_pattern: ROADMAP.md + + - name: Sync Discord + if: steps.update.outputs.changed == 'true' + run: python scripts/roadmap/sync_discord.py + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} <<<<<<< HEAD DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} From feae0f5bd5757eb719ed4ad69200da0d65056c6c Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 22:51:49 +0200 Subject: [PATCH 69/81] Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow. --- scripts/roadmap/sync_roadmap.py | 169 ++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/scripts/roadmap/sync_roadmap.py b/scripts/roadmap/sync_roadmap.py index 68a2924..b5cd832 100644 --- a/scripts/roadmap/sync_roadmap.py +++ b/scripts/roadmap/sync_roadmap.py @@ -388,5 +388,174 @@ def main() -> None: f.write(f"changed={'true' if changed else 'false'}\n") +if __name__ == "__main__": + main() +#!/usr/bin/env python3 +""" +Reads the GitHub event that triggered this workflow run (an issue or PR +change) and updates the matching line in ROADMAP.md to one of three +states: + + [ ] Lists — #34 not started + [ ] 🚧 Lists — #34 in progress (assigned / open PR) + [x] Lists — #34 done (merged / issue closed) + +GitHub's task-list rendering only recognizes [ ] and [x] as real, +interactive checkboxes — anything else (like a bare [-]) is just +literal text with no checkbox widget. So the checkbox itself stays +strictly boolean (done / not done), and "in progress" is layered on +as a 🚧 badge in the visible text instead of a third bracket state. + +This only touches roadmap lines that already reference an issue, e.g.: + + * [ ] Lists — #34 + +Lines with no "— #N" suffix are left alone — link an issue to a lesson +by adding that suffix, and the automation picks it up from then on. +""" + +import json +import os +import re + +ROADMAP_PATH = "ROADMAP.md" +WIP_BADGE = "🚧" + +# Internal state codes (unchanged from before): " " = not started, +# "-" = in progress, "x" = done. Only how they're RENDERED changes. +STATE_RENDER = { + " ": {"check": " ", "badge": ""}, + "-": {"check": " ", "badge": f"{WIP_BADGE} "}, + "x": {"check": "x", "badge": ""}, +} + +# Matches e.g. " * [ ] 🚧 Lists — #34" and captures the checkbox, +# an optional WIP badge, and the issue number — everything else on +# the line is left untouched. +LINE_RE = re.compile( + r"^(?P\s*\*\s*\[)(?P[ x])(?P\]\s*)" + rf"(?P{WIP_BADGE}\s*)?" + r"(?P.*?—\s*#)(?P\d+)(?P.*)$" +) + + +def current_state(check: str, badge: str | None) -> str: + if check == "x": + return "x" + return "-" if badge else " " + + +# Matches "Closes #12", "Fixes #34", "Resolves #7", etc. (repeatable, case-insensitive) +ISSUE_REF_RE = re.compile( + r"(?:clos(?:e[sd]?)|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)", re.IGNORECASE +) + + +def marker_for_issue_event(event: dict) -> dict[int, str]: + action = event["action"] + issue_number = event["issue"]["number"] + + if action == "assigned": + return {issue_number: "-"} + if action == "unassigned": + return {issue_number: " "} + if action == "closed": + return {issue_number: "x"} + if action == "reopened": + has_assignee = bool(event["issue"].get("assignees")) + return {issue_number: "-" if has_assignee else " "} + return {} + + +def marker_for_pr_event(event: dict) -> dict[int, str]: + action = event["action"] + pr = event["pull_request"] + body = pr.get("body") or "" + issue_numbers = {int(n) for n in ISSUE_REF_RE.findall(body)} + if not issue_numbers: + return {} + + if action in ("opened", "ready_for_review"): + marker = "-" + elif action == "closed": + marker = "x" if pr.get("merged") else "-" + else: + return {} + + return {n: marker for n in issue_numbers} + + +def load_event() -> dict: + with open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8") as f: + return json.load(f) + + +def compute_updates() -> dict[int, str]: + event_name = os.environ["GITHUB_EVENT_NAME"] + event = load_event() + + if event_name == "issues": + return marker_for_issue_event(event) + if event_name == "pull_request" or event_name == "pull_request_target": + return marker_for_pr_event(event) + return {} + + +def apply_updates(updates: dict[int, str]) -> bool: + with open(ROADMAP_PATH, encoding="utf-8") as f: + lines = f.readlines() + + changed = False + for i, line in enumerate(lines): + m = LINE_RE.match(line.rstrip("\n")) + if not m: + continue + + issue = int(m.group("issue")) + if issue not in updates: + continue + + new_state = updates[issue] + old_state = current_state(m.group("check"), m.group("badge")) + if old_state == new_state: + continue + + render = STATE_RENDER[new_state] + lines[i] = ( + m.group("prefix") + + render["check"] + + m.group("mid") + + render["badge"] + + m.group("body") + + m.group("issue") + + m.group("rest") + + "\n" + ) + changed = True + print(f"#{issue}: [{old_state}] -> [{new_state}]") + + if changed: + with open(ROADMAP_PATH, "w", encoding="utf-8") as f: + f.writelines(lines) + + return changed + + +def main() -> None: + updates = compute_updates() + if not updates: + print("No linked roadmap issue affected by this event — nothing to do.") + changed = False + else: + changed = apply_updates(updates) + if not changed: + print("Matching roadmap line(s) already up to date.") + + github_output = os.environ.get("GITHUB_OUTPUT") + if github_output: + with open(github_output, "a", encoding="utf-8") as f: + f.write(f"changed={'true' if changed else 'false'}\n") + + if __name__ == "__main__": main() From dd52e088dde54779387aef2ac6538b285fc93fda Mon Sep 17 00:00:00 2001 From: razorblade23 Date: Sun, 27 Sep 2026 23:28:36 +0200 Subject: [PATCH 70/81] Added a reconcile step for manual triggering and scheduled at 04:00 AM --- .github/workflows/sync_roadmap_status.yml | 100 ---------------------- 1 file changed, 100 deletions(-) diff --git a/.github/workflows/sync_roadmap_status.yml b/.github/workflows/sync_roadmap_status.yml index 2e4dc49..4367879 100644 --- a/.github/workflows/sync_roadmap_status.yml +++ b/.github/workflows/sync_roadmap_status.yml @@ -108,106 +108,6 @@ jobs: run: python scripts/roadmap/sync_discord.py env: DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} - - reconcile: - if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: main - - - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - - name: Reconcile ROADMAP.md with issue states - id: update - run: python scripts/roadmap/reconcile_roadmap.py - env: - GITHUB_REPOSITORY: ${{ github.repository }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Commit ROADMAP.md - if: steps.update.outputs.changed == 'true' - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "chore: reconcile roadmap status [skip ci]" - file_pattern: ROADMAP.md - - - name: Sync Discord - if: steps.update.outputs.changed == 'true' - run: python scripts/roadmap/sync_discord.py - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} - - reconcile: - if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: main - - - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - - name: Reconcile ROADMAP.md with issue states - id: update - run: python scripts/roadmap/reconcile_roadmap.py - env: - GITHUB_REPOSITORY: ${{ github.repository }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Commit ROADMAP.md - if: steps.update.outputs.changed == 'true' - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "chore: reconcile roadmap status [skip ci]" - file_pattern: ROADMAP.md - - - name: Sync Discord - if: steps.update.outputs.changed == 'true' - run: python scripts/roadmap/sync_discord.py - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} -<<<<<<< HEAD - DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} - - reconcile: - if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: main - - - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - - name: Reconcile ROADMAP.md with issue states - id: update - run: python scripts/roadmap/reconcile_roadmap.py - env: - GITHUB_REPOSITORY: ${{ github.repository }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Commit ROADMAP.md - if: steps.update.outputs.changed == 'true' - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "chore: reconcile roadmap status [skip ci]" - file_pattern: ROADMAP.md - - - name: Sync Discord - if: steps.update.outputs.changed == 'true' - run: python scripts/roadmap/sync_discord.py - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} ======= >>>>>>> 2bfe0cf (Added automated scripts for pushing ROADMAP updates automaticly on Issue assigment. Changed ROADMAP.md to fit new workflow.) DISCORD_MESSAGE_IDS: ${{ vars.DISCORD_MESSAGE_IDS }} \ No newline at end of file From 8ffe44b242ba43a0e2fe914d106e990c5cf8d1e2 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:56:05 +0000 Subject: [PATCH 71/81] chore: reconcile roadmap status [skip ci] --- ROADMAP.md | 102 ++++++++++++++--------------------------------------- 1 file changed, 26 insertions(+), 76 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 2667f8c..36bc863 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -9,16 +9,11 @@ This may be subject to change. ## Roadmap 1. Introduction * [x] How course works? -<<<<<<< HEAD * [x] Motivation and Mindset + * [ ] Asking for Help — #32 * [ ] Asking for Help (WIP) — #32 * [ ] Asking for Help — #32 * [ ] Join the Community — #33 -======= - * [ ] Motivation and Mindset - * [ ] Asking for Help (WIP) - * [x] Join the Community ->>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) * [x] Computer Science basics, Programming and Python 2. Prerequisites * [x] Software Installation @@ -35,59 +30,38 @@ This may be subject to change. * [x] Arithmetic and String Operations, Comparisons * [x] User Input and Conditionals * [x] Loops -<<<<<<< HEAD - * [-] Data Structures - * [-] List - * [-] Tuple - * [-] Set - * [-] Dictionary - * [ ] Functions - * [ ] Project 1 -5. Modules, Working with Files and Error Handling - * [ ] Working with multiple files (`__init.py__`, directory structure, etc...) - * [ ] Opening, Closing and Manipulating files - * [ ] Error Handling (`try-except-else-finally`) - * [ ] Custom Exceptions - * [ ] Defensive Coding patterns - * [ ] Working with structured data (`json`, `csv`, etc...) - * [ ] Project 2 -6. OOP, Virtual Environments and third party libraries, Working with APIs - * [ ] Classes and OOP - * [ ] Usage and setup of virtual environments - * [ ] Installation of third party libraries - * [ ] Working with APIs - * [ ] Project 3 - *probably: * weather app -7. Working on Projects, Solving bugs, Reading errors -======= 5. Data Structures * [ ] Lists — #57 * [ ] Tuples — #58 * [ ] Sets — #59 * [ ] Dictionaries — #60 * [ ] Coprehensions (`list`, `dict` `set`) — #61 - * [x] Lists (WIP) - * [x] Tuples (WIP) - * [x] Sets (WIP) - * [x] Dictionaries (WIP) - * [x] Coprehensions (`list`, `dict` `set`) (WIP) 6. Code Organization * [ ] Functions — #62 * [ ] Scope and Namespaces (LEGB rule) — #63 - * [ ] 🚧 Type Hints — #64 - * [ ] 🚧 Modules — #65 + * [ ] Type Hints — #64 + * [ ] Modules — #65 7. Capstone Project 1 - * [ ] Problem Solving - * [ ] Problem Solving - Fizz-Buzz Example - * [ ] Capstone Project - **Hangman game** + * [ ] Problem Solving — #66 + * [ ] Problem Solving - Fizz-Buzz Example — #67 + * [ ] Capstone Project - **Hangman game** — #68 8. Errors, Debugging, I/O - * [ ] Functions - * [ ] Scope and Namespaces (LEGB rule) * [ ] Understanding Errors and Error Handling + * [ ] `logging` module + * [ ] Debugging tehniques * [ ] File Handling - * [ ] Modules -7. Capstone Project 1 - * [ ] Problem Solving - * [ ] Problem Solving - Fizz-Buzz Example +9. Capstone Project 2 + * [ ] Git Workflow: Branches and Pull Requests + * [ ] Revisiting Project 1 (hangman game): + * Creating branch, adding features, merging back to `main` + * Loading *words* from external file + * Catching and logging errors + * [ ] Capstone Project +10. Intermediate Python + * [ ] Decorators + * [ ] Generators + * [ ] Context Managers +11. Capstone Project 3 * [ ] Capstone Project 12. Built-in and Modules * [-] Data Structures @@ -157,24 +131,21 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module -9. Third-party Modules + * [ ] `re` module +13. Third-party Modules * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file - * [ ] ? Linting, Formatting, Type Checking (`ruff`, `mypy`) ? -14. Capstone Project 4 +10. Capstone Project 2 * [ ] Clean Code Priciples * [ ] Capstone Project - * [ ] Testing Your Code (`pytest`) - * [ ] Revisit Project 4 - * Develop a testing suite for the project -15. Object Oriented Programming - Part 1 +11. Object Oriented Programming - Part 1 * [ ] Introduction to classes and instances * [ ] Methods (instance, class, static) * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -16. Capstone Project 5 +12. Capstone Project 3 * [ ] Capstone Project -17. Object Oriented Programming - Part 2 +13. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) 18. Capstone Project 6 10. Third-party Modules @@ -194,25 +165,4 @@ This may be subject to change. * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) 15. Capstone Project 4 * [ ] Capstone Project -======= -10. Third-party Modules -======= -9. Third-party Modules ->>>>>>> 71088b3 (Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson) - * [ ] Virtual Environments - * [ ] Using `pip` and `requirements.txt` - * [ ] Creating python package - `pyproject.toml` file -10. Capstone Project 2 - * [ ] Clean Code Priciples - * [ ] Capstone Project -11. Object Oriented Programming - Part 1 - * [ ] Introduction to classes and instances - * [ ] Methods (instance, class, static) - * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -12. Capstone Project 3 - * [ ] Capstone Project -13. Object Oriented Programming - Part 2 - * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -14. Capstone Project 4 - * [ ] Capstone Project >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) From be09707a573474e3dd8ad3c1b07cad0edec55894 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sat, 12 Sep 2026 09:33:50 +0200 Subject: [PATCH 72/81] Updated lists lessons and ROADMAPmd --- ROADMAP.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index 36bc863..6ec4fd7 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -131,6 +131,7 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module +<<<<<<< HEAD * [ ] `re` module 13. Third-party Modules * [ ] Virtual Environments @@ -166,3 +167,22 @@ This may be subject to change. 15. Capstone Project 4 * [ ] Capstone Project >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) +======= +10. Third-party Modules + * [ ] Virtual Environments + * [ ] Using `pip` and `requirements.txt` + * [ ] Creating python package - `pyproject.toml` file +11. Capstone Project 2 + * [ ] Clean Code Priciples + * [ ] Capstone Project +12. Object Oriented Programming - Part 1 + * [ ] Introduction to classes and instances + * [ ] Methods (instance, class, static) + * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) +13. Capstone Project 3 + * [ ] Capstone Project +14. Object Oriented Programming - Part 2 + * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) +15. Capstone Project 4 + * [ ] Capstone Project +>>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) From 20d10be0103f34f4c1b84ae37b81d58799434c23 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Sun, 13 Sep 2026 16:57:49 +0200 Subject: [PATCH 73/81] Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson --- ROADMAP.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 6ec4fd7..bdb2259 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -131,6 +131,7 @@ This may be subject to change. * [ ] `pathlib` / `os` module * [ ] `csv` module * [ ] `sys` module +<<<<<<< HEAD <<<<<<< HEAD * [ ] `re` module 13. Third-party Modules @@ -169,20 +170,23 @@ This may be subject to change. >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) ======= 10. Third-party Modules +======= +9. Third-party Modules +>>>>>>> 71088b3 (Fixed "WHATS'S NEXT" in dictionary lesson and added "WHAT'S NEXT" section to coprehensions lesson) * [ ] Virtual Environments * [ ] Using `pip` and `requirements.txt` * [ ] Creating python package - `pyproject.toml` file -11. Capstone Project 2 +10. Capstone Project 2 * [ ] Clean Code Priciples * [ ] Capstone Project -12. Object Oriented Programming - Part 1 +11. Object Oriented Programming - Part 1 * [ ] Introduction to classes and instances * [ ] Methods (instance, class, static) * [ ] Dunder Methods (`__str__`, `__repr__`, etc...) -13. Capstone Project 3 +12. Capstone Project 3 * [ ] Capstone Project -14. Object Oriented Programming - Part 2 +13. Object Oriented Programming - Part 2 * [ ] Four Pillars of Object-Oriented Programming (Encapsulation, Abstraction, Inheritance, Polymorphism) -15. Capstone Project 4 +14. Capstone Project 4 * [ ] Capstone Project >>>>>>> f8b636d (Updated lists lessons and ROADMAPmd) From 6867475a7602a16d6149814f274c03721773ef57 Mon Sep 17 00:00:00 2001 From: amotech Date: Fri, 2 Oct 2026 22:35:25 +0000 Subject: [PATCH 74/81] test3 over-ride for corr... --- .../01-introduction/03-asking-for-help.md | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index 4c9f46f..7460772 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -62,7 +62,39 @@ Steps to format your code: ### 4. What to Expect Next ➡ Once you have submitted your help request, sit down tight and the appropriate help will be sent straight to you. -## Introduction -This lesson is intended to help you become good in seeking for help +If unfortunately the help response delays or never comes, use the next approach which is _Who To Ask_. + + +## Who to Ask for Help 🧔🏻❔ +subs: +* Ask yourself +* Ask someone with experience +* Ask a trusted community +* Ask an Ai agent + +### 1. Ask Yourself Before Anyone +You may say, why myself, i don't know?—Ofcourse you know all the answers to your own questions most of the times. **Ask yourself why, why did the error come; Ask yourself how, how did the error come; and Ask yourself what, what brought up a particular error** :(. You are not actually finding the correct solution to the cause of the error with these questions overnight (as if it was a magic :)), **but** what you are doing is you are training your thinking, which may help you think creatively gradually—to solve future problems. "Problem solving requires a creative and effective thinking"—Baldwin.J,. college success(2021). + +After you have had your answers to those three question, store them safely as we will learn how they might become useful later in this lesson. + +### 2. Ask Someone with Experience +Why ask someone with experience?—An experienced programmer, specifically python programmer, knows how to solve or debug almost every bug or error respectively. Therefore asking an experienced person means there is a higher probability you will get a solution to an/a error/bug. + +Now let see how your answers at the _ask yourself_ sub gets useful here. Compare your answers obtained at the _ask yourself_ sub to the ones you obtained from the experienced programmer and **Ask youself one more time—what did i missed?**—Keep this particular answer to yourself (treat it as important), it might help you in your future decisions when debugging other or similar errors later on. + +### 3. Ask a Trusted Community +Though there isn't a full guarantee that a community will contain only experienced programmers,—That is there would be beginners, intermediates and experts—but there are people with at least an experience if not much, these people might have already at least solved a bug which you just met, and could share with you how they handled it—which might be a fantastic approach you could learn also. + +Therefore asking verified communities like the stackoverflow, github, telegram groups, reddit, discord and others i could'nt mention—though one should proceed this with caution—is a must once you are learning the python or any other programming langauge. + +### 4. Ask an AI Agent +AI tools or agents are a smart way to debug errors faster, but the question is—Does the AI agent know the best approch to avoid future code breaks? + +This does not neccessarily mean using AI assistance for debugging errors is bad. But for best decision sake; That is if you know enough or understand how to select the best approach out of the many provided by the AI model, then you are encouraged to proceed with this approach—the advice is simple, that is use AI to recall the best solutions you already know quickly and not to decide the best solutions for you. + +This really counts in a serious project or even in the real world practices, but it is also a good thing to keep it in practice now—even if you are learning. + + +## Where to Ask for Help +- _work in progress_ -## Work in progress From 647bdbd8802dbd4e61023dfc575865500f83fec7 Mon Sep 17 00:00:00 2001 From: amotech Date: Sat, 3 Oct 2026 20:15:29 +0000 Subject: [PATCH 75/81] v0.3 ask4help --- .../01-introduction/03-asking-for-help.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/curriculum/01-introduction/03-asking-for-help.md b/curriculum/01-introduction/03-asking-for-help.md index 7460772..e3ee688 100644 --- a/curriculum/01-introduction/03-asking-for-help.md +++ b/curriculum/01-introduction/03-asking-for-help.md @@ -17,7 +17,7 @@ In this lesson you will learn how to get help whenever you need it. And by the e ## Lesson outline 📝 * How to Get Help * Who to Ask for Help -* Where to Ask for Help +* Where to Ask for Help (**Under Construction...**) ## How to Get Help ❔ Steps to follow to get help: @@ -96,5 +96,20 @@ This really counts in a serious project or even in the real world practices, but ## Where to Ask for Help +Subs: +- Ask the social media +- Ask in learning centers + +### 1. Ask the Social Media +At least anyone who owns a smart device has an account registered on a social media platform—Some popularly known ones are: _WhatsApp, Facebook, Twitter, TikTok, Reddit, Discord, etc._—and on these platform so might be as well all kinds of programmers—experienced ones specifically. + +__Note__: +```text +In case it comes to pass that you are not registered on any of these platforms, just register on any of them to get started. +``` +**Don't just ASK** _"Hello everyone i need help with fixing a bug"_—without a link to code, media files, just this text or similar— this will actually lead others to either just leave a 'like' or do nothing. _What is the right way to ask the social media?_— **ASK by** including a clear title, clear content/message describing the error process and your expectations, a link to the code somewhere or a screenshot of the code, and optionally the methods you have used that never worked. + +### 2. Ask in Learning Centers + - _work in progress_ From 68d1cc50ace355534362a9a70764cfbf81fb7b47 Mon Sep 17 00:00:00 2001 From: tajirdev Date: Sat, 3 Oct 2026 15:54:22 +0300 Subject: [PATCH 76/81] feat(curriculum): add lesson on functions (#62) --- .../06-code-organization/01-functions.md | 220 ++++++++++++++++++ .../06-code-organization/_category_.json | 8 + 2 files changed, 228 insertions(+) create mode 100644 curriculum/06-code-organization/01-functions.md create mode 100644 curriculum/06-code-organization/_category_.json diff --git a/curriculum/06-code-organization/01-functions.md b/curriculum/06-code-organization/01-functions.md new file mode 100644 index 0000000..39cfa2f --- /dev/null +++ b/curriculum/06-code-organization/01-functions.md @@ -0,0 +1,220 @@ +--- +id: functions +title: Reusable Code with Functions +sidebar_label: Functions +sidebar_position: 1 +lesson: true +isDraft: false +--- +# Reusable Code with Functions + +Throughout this course, you have already been using functions without necessarily realizing it, like **print()** and **len()**. + +Up to this point all of our python scripts have executed straight from top to bottom. If you needed to perform the same calculation three times you had to copy and paste the exact same block three times. + +In this lesson, we will learn how to bundle operations into reusable, named blocks of code called **functions** + +## Lesson OverView {#overview} + +At the end of this lesson you will” + +- Define your own custom function using **def** keyword +- Call functions and pass data into them using parameters and arguments +- Provide fallback options using default parameter values +- Send computed data back to your program using **return** +- Understand the critical distinction between **return** and **print()** +- Understand between built-in and user-defined functions. + +## Conceptual Overview + +**Functions**: is reusable block of code that perform a specific task which can be called multiple times with different inputs and returns the value + +When talking about function think like self-contained machine: + +1. **Input**: you feed data into it (arguments) +2. **Process**: it carries out a sequence of instructions. +3. **Output**: it produce a result and hands it back to you (return) + +:::tip [The DRY Principle] + One thing to know by organizing code into function, your programs follow the DRY principle : Don’t Repeat Yourself +::: + +## Defining and Calling Functions + +A function is defined using the **def** keyword followed by descriptive name in **snake_case** , parentheses () and colon : .Everything inside function must be indented + +Example: + +```python interactive debuge + +def display_welcome(): + + print('welcome to our python function') + +``` + +Above is the function which when we run should show you the message **welcome to our python function** but when your run it now nothing will display in terminal this because we have not call it + +In order to see the function output we will have to call it here is now full code + +```python interactive + +def display_welcome(): + + print('welcome to our python function') + +#Calling the function + +display_welcome() + +``` + +At the bottom of our function we have written the function name with parenthesis **display_welcome()** this is how to call the function + +:::info +Always use descriptive action verbs for function names such as calculate_total, display_welcome +::: + + +## Parameters and Arguments + +Function become more powerful and useful when they can operate on varying inputs + +**Parameter**: the variable listed inside the parentheses in the function definition(act as place holder) + +**Argument**: the actual concrete value sent to the function when it called + +```python interactive + +def greet_customer(name):# name is parameter + + print("hello", name) + +greet_customer("Alfred")#Alfred is argument +``` + +you can pass multiple parameters by separating them by comma + +```python interactive + +def greet_customer(name,address) + print "hello", name,"from", address + +#And calling will be + +greet_customer("Bob","dubai") + +``` + +## Default parameter + +You can provide fallback value for parameter using the assignment operator (=) in the function definition. This help if caller does not provide argument Python uses the default value + +```python interactive + +def add_numbers(a,b=2): + + return a + b + +print(add_numbers(2,3)) #result 5 + +print(add_numbers(10)) #result 12 + +``` + +:::[Order of Default parameters] +info Parameters with default values must always be placed **after** parameters without default values in your function definition. +::: + + +## Returning Values vs Printing + +The different between **print()** and **return** is one ot the most critical concepts for beginners to master: + +- **print()** simply displays text on your screen for human to read.The rest of your program cannot capture or do any further work with that displayed text +- **return** hands a computed value back to the caller. This allows your program to capture the result in a variable and pass it to other calculations + +```python interactive debug + +def calculate_subtotal(quantity, unit_price): + + total = quantity * unit_price + + return total + +# We capture the returned value in a variable + +order_total = calculate_subtotal(3, 15.0) + +# Now we can perform further math on it + +final_total = order_total + 5.0 # Adding a $5 shipping fee + +print("Final amount due:", final_total) + +``` + +:::tip +If a function finishes without an explicit return statement, Python automatically returns None. +::: + + +## Function Types +Broadly speaking, function in Python fall into two categories: +- **Built-in function**: Tools that pre-packaged with python, ready to use anywhere without any extra setup(such as print(), len(), type() and range()) +- **User-defined function**: Customer function you write yourself using **def** keyword to solve the specific needs of your program + + +:::tip +apart from these function there other types of function you can study more from here [**types of functions**](https://www.geeksforgeeks.org/python/python-functions) +::: + + + + + +## Deepen your Knowledge + +:::explore +[**Learn More: Official Documentation & Best Practices**] Read the following resources to build a deeper mental model of how arguments and documentation work in Python: + +1. Read [**Python Tutorial: Defining Functions**](https://docs.python.org/3/tutorial/controlflow.html#23defining-functions) (Sections 4.7, 4.7.1, and 4.7.2). Pay close attention to how Python handles positional arguments versus keyword arguments. +2. Read **Section 4.7.7 (Documentation Strings)** in the official documentation to see how professionals document what a function does. ::: + +## Check Knowledge + +Test your understanding with the following questions. Some questions require research using the links above: + +1. What happens if you define a parameter without a default value *after* a parameter that has a default value (e.g., def func(a=1, b):)? +2. What value does a function return if it contains no return statement? +3. What is a **Docstring**, where is it placed inside a function, and what syntax is used to define it? +4. What is the difference between passing an argument by position versus passing it by keyword? + +## Exercise + +Visit our [python-exercises repository](https://github.com/ThePythonLedger/python-exercises) to update your local copy: + +1. Fetch and pull the latest changes from upstream/main. +2. Locate the exercise directory exercises/foundations/05_functions. +3. Run pytest to see the test suite. +4. Implement the required functions one by one, removing the @pytest.mark.skip decorator as you pass each level. + +## Assignment {#assignment} + +Return to your simple-python-shop project from previous lessons. We will refactor our script to use modular functions rather than top-level code. + +You will do this assignment on your local machine: + +1. Open your simple-python-shop directory in your code editor. +2. Open main.py and refactor your logic into the following dedicated functions: + - calculate_subtotal(price, quantity): Multiplies the unit price by quantity and **returns** the subtotal as a float. + - calculate_tax(subtotal, tax_rate=0.07): Calculates the tax amount with a default rate of 7% (0.07) and **returns** the tax amount. + - format_receipt(shop_name, item_name, quantity, total): Takes shop details and **prints** a multi-line formatted receipt to the console. +3. Call your functions using your shop's item data and print the resulting receipt. +4. Verify your program runs cleanly with python main.py. +5. Stage, commit, and push your changes to your remote GitHub repository. + +## What's Next {#next-lesson} + +Now that we can package code into reusable functions, an important question arises: where do the variable defined inside a function live and who can access them? +In the next lesson we will explore **Scope and Namespace(the LEGB rule) to understand how Python looks up variable names and how to prevent unintended side effects in your code \ No newline at end of file diff --git a/curriculum/06-code-organization/_category_.json b/curriculum/06-code-organization/_category_.json new file mode 100644 index 0000000..82a42f8 --- /dev/null +++ b/curriculum/06-code-organization/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Code Organization", + "position": 6, + "link": { + "type": "generated-index", + "description": "Structuring Python programs with functions, scopes, type hints, and modules." + } +} \ No newline at end of file From b0894b675825098b7335f9c9bf0b0122f06b82aa Mon Sep 17 00:00:00 2001 From: tajirdev Date: Sat, 3 Oct 2026 16:11:14 +0300 Subject: [PATCH 77/81] fixed small typo and code syntax issues --- curriculum/06-code-organization/01-functions.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/curriculum/06-code-organization/01-functions.md b/curriculum/06-code-organization/01-functions.md index 39cfa2f..37b0dd8 100644 --- a/curriculum/06-code-organization/01-functions.md +++ b/curriculum/06-code-organization/01-functions.md @@ -97,8 +97,8 @@ you can pass multiple parameters by separating them by comma ```python interactive -def greet_customer(name,address) - print "hello", name,"from", address +def greet_customer(name,address): + print ("hello", name,"from", address) #And calling will be @@ -122,8 +122,9 @@ print(add_numbers(10)) #result 12 ``` -:::[Order of Default parameters] -info Parameters with default values must always be placed **after** parameters without default values in your function definition. +:::info + + Parameters with default values must always be placed **after** parameters without default values in your function definition. ::: @@ -179,7 +180,8 @@ apart from these function there other types of function you can study more from [**Learn More: Official Documentation & Best Practices**] Read the following resources to build a deeper mental model of how arguments and documentation work in Python: 1. Read [**Python Tutorial: Defining Functions**](https://docs.python.org/3/tutorial/controlflow.html#23defining-functions) (Sections 4.7, 4.7.1, and 4.7.2). Pay close attention to how Python handles positional arguments versus keyword arguments. -2. Read **Section 4.7.7 (Documentation Strings)** in the official documentation to see how professionals document what a function does. ::: +2. Read **Section 4.7.7 (Documentation Strings)** in the official documentation to see how professionals document what a function does. +::: ## Check Knowledge From e3f79da3d1fa90f0fb6f2710169d420ce05b82ed Mon Sep 17 00:00:00 2001 From: tajirdev Date: Sat, 3 Oct 2026 17:33:02 +0300 Subject: [PATCH 78/81] fixed [] issue and typo issues --- curriculum/06-code-organization/01-functions.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/curriculum/06-code-organization/01-functions.md b/curriculum/06-code-organization/01-functions.md index 37b0dd8..f866f36 100644 --- a/curriculum/06-code-organization/01-functions.md +++ b/curriculum/06-code-organization/01-functions.md @@ -35,7 +35,7 @@ When talking about function think like self-contained machine: 2. **Process**: it carries out a sequence of instructions. 3. **Output**: it produce a result and hands it back to you (return) -:::tip [The DRY Principle] +:::tip The DRY Principle One thing to know by organizing code into function, your programs follow the DRY principle : Don’t Repeat Yourself ::: @@ -45,7 +45,7 @@ A function is defined using the **def** keyword followed by descriptive name in Example: -```python interactive debuge +```python interactive debug def display_welcome(): @@ -167,7 +167,7 @@ Broadly speaking, function in Python fall into two categories: :::tip -apart from these function there other types of function you can study more from here [**types of functions**](https://www.geeksforgeeks.org/python/python-functions) +Apart from these function there other types of function you can study more from here [**types of functions**](https://www.geeksforgeeks.org/python/python-functions) ::: @@ -177,7 +177,7 @@ apart from these function there other types of function you can study more from ## Deepen your Knowledge :::explore -[**Learn More: Official Documentation & Best Practices**] Read the following resources to build a deeper mental model of how arguments and documentation work in Python: +**Learn More: Official Documentation & Best Practices** Read the following resources to build a deeper mental model of how arguments and documentation work in Python: 1. Read [**Python Tutorial: Defining Functions**](https://docs.python.org/3/tutorial/controlflow.html#23defining-functions) (Sections 4.7, 4.7.1, and 4.7.2). Pay close attention to how Python handles positional arguments versus keyword arguments. 2. Read **Section 4.7.7 (Documentation Strings)** in the official documentation to see how professionals document what a function does. From 85982933b5f481eb5e88ebd52bc94618a1c208a9 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 23 Sep 2026 12:15:38 +0200 Subject: [PATCH 79/81] Updated "assigment" to first 3 lessons containing it --- curriculum/03-git-basics/03-git-basics.md | 31 ++++++++++--- .../01-output-variable-datatypes.md | 23 +++++----- .../02-math-stringops-comparisons.md | 44 ++++++++++++------- .../03-user-input-and-conditionals.md | 37 ++++++++++------ curriculum/04-python-foundations/04-loops.md | 7 ++- 5 files changed, 94 insertions(+), 48 deletions(-) diff --git a/curriculum/03-git-basics/03-git-basics.md b/curriculum/03-git-basics/03-git-basics.md index 462b6cf..037c2b4 100644 --- a/curriculum/03-git-basics/03-git-basics.md +++ b/curriculum/03-git-basics/03-git-basics.md @@ -25,11 +25,24 @@ Before starting with commands, it's useful to get to know ourself with some word * **Commit**: A snapshot of your code at the time of creating **commit**. Commits are what allow you to undo your changes to any older commit at any time. * **Branch**: A parallel codebase for you to experiment with and build new features without affecting the **main** branch * **Pull Request (PR)**: When work on the branch is finished, you issue a pull request to your *main* branch so changes can be *merged*. -* **Remote**: A copy of your repository NOT on your local machine (etc.: *Github*) +* **Remote**: A copy of your repository NOT on your local machine (etc.: *GitHub*) + +:::tip +Do not worry about what these words mean just yet or try to remember it all. We will use `git` commonly throuout the course, and you will get plenty of exercise in using it. +::: +## Assignment {#assignment} +1. To keep things organized while you work on projects, choose a directory on your local computer where you will store all of them and `cd` into it. For example create a directory called `Projects` in your `Documents` directory. For the rest of the course, we will assume your `Projects` directory has the following path: `~/Documents/Projects`. +2. Now we need to create a directory which we will use to store our **assigment** project which we will evolve after each lesson. Create a new directory by executing `mkdir simple-bookstore`, then `cd` into it by executing `cd simple-bookstore`. +3. We need to tell `git` to start tracking changes in our directory, which is called **initialization**. Run `git init` command to let `git` know that you want to start tracking this directory. +4. Now we will create our first file: `README.md`. This file serves as description of your project and usually contains information on running your projects. We will not worry about this now, just open your code editor in that directory by executing `code .` command (**NOTE:** don't forget the dot `.` at the end of the command). Create a new file with the name `README.md` and write some content in it, like: + ``` + This is the start of my python journey! + ``` + Or whatever contents you want. ## Assignment {#assignment} 1. Choose a directory on your local computer where you will store all of your projects and `cd` into it. For example create a directory called `Projects` in your `Documents` directory. For the rest of the course, we will assume your `Projects` directory has the following path: `~/Documents/Projects`. -2. Create a new directory by executing `mkdir simple-python-shop`, then `cd` into it by executing `cd simple-python-shop`. +2. Create a new directory by executing `mkdir simple-bookstore`, then `cd` into it by executing `cd simple-bookstore`. 3. Initialize `git` repository by executing `git init` command. This tells `git` to start tracking for changes in our directory. 4. Let's create a `README.md` file as every good repository should have one. Open your code editor in that directory by executing `code .` command (**NOTE:** don't forget the `.` at the end of the command). Create a new file with the name `README.md` and write some content in it, like: ``` @@ -39,10 +52,18 @@ Before starting with commands, it's useful to get to know ourself with some word 5. Let's check the status of our repository by executing `git status` command. You will see your `README.md` in the section **untracked files**. This means `git` knows about your file, but it's not part of the snapshot it will create, so let's fix that in the next step. 6. By executing `git add README.md` we say to `git` that we want to add that file to **staging area** which is like a space where git is aware of your files and which will be included in the snapshot (commit). Like saying a photographer to line up and frame the shot. Now we take the actuall snapshot (commit) in the next step. 7. Execute `git commit -m "Add README file with initial content"` command which tells `git` to make the actuall snapshot (or **commit**). `-m` stands for **message** and its **required** in *commit* command, and not supplying it will open your default terminal text editor to enter the message. Message should be short but descriptive note explaining what you changed and why. -8. Now let's upload our files to *Github* (or **push** the changes we made). First we need to create a repository in our *Github*. Go to [github.com/new](https://github.com/new) and enter the name for your new remote repository. You can use the same name as your local directory: `simple-python-shop`. Then choose visibility setting (public or private). **DO NOT** create files *Github* offers: *README*, *.gitignore*, *license*; we will do these manually. Click on the green *Create repository* button. -9. Github will offer varius ways of getting things done, but the main thing you should be looking for is the command starting with `git remote add origin`. Copy that whole line and paste it in your terminal (be sure you are in our current directory (`simple-python-shop`)). The line should look something like `git remote add origin https://github.com/your-username/simple-python-shop.git`. Execute the command to add our remote repository as **remote** to our current git repository, so we can **push** the changes we made to online repository. +8. Now let's upload our files to *Github* (or **push** the changes we made). First we need to create a repository in our *Github*. Go to [github.com/new](https://github.com/new) and enter the name for your new remote repository. You can use the same name as your local directory: `simple-bookstore`. Then choose visibility setting (public or private). **DO NOT** create files *Github* offers: *README*, *.gitignore*, *license*; we will do these manually. Click on the green *Create repository* button. +9. Github will offer varius ways of getting things done, but the main thing you should be looking for is the command starting with `git remote add origin`. Copy that whole line and paste it in your terminal (be sure you are in our current directory (`simple-bookstore`)). The line should look something like `git remote add origin https://github.com/your-username/simple-bookstore.git`. Execute the command to add our remote repository as **remote** to our current git repository, so we can **push** the changes we made to online repository. 10. Now run `git push -u origin main` to send files to your *remote* we just added in the previus step. The `-u` flag is used only **first time** you push to set up *tracking connections* so in later pushes, we can just do `git push`. -11. Check your *Github* for pushed code. You should see your `README.md` sitting there on your repository view. Congratulations! You’ve just mastered the fundamental workflow of Git and GitHub. +11. Check your *Github* for pushed code. You should see your `README.md` sitting there on your repository view. Congratulations! You've just mastered the fundamental workflow of Git and GitHub. + +:::tip +In the above step 6, we executed `git add README.md`. This is fine when you have a few files to add to staging area, but what if there are dozens, or hundreds? + +Git helps us out with `git add .` (notice the dot `.`) which will add **all** unstaged files to staging area. + +This may not be what you always want, but it is a nice shortcut. +::: ## What's Next {#next-lesson} We are finally done with introductions and essential setup so we can start with python lessons. Let's learn. \ No newline at end of file diff --git a/curriculum/04-python-foundations/01-output-variable-datatypes.md b/curriculum/04-python-foundations/01-output-variable-datatypes.md index ffececc..f16113f 100644 --- a/curriculum/04-python-foundations/01-output-variable-datatypes.md +++ b/curriculum/04-python-foundations/01-output-variable-datatypes.md @@ -157,21 +157,18 @@ Visit our [python-excercise repository](https://github.com/ThePythonLedger/pytho After cloning, try to solve [excercise-1](https://github.com/ThePythonLedger/python-exercises/tree/main/exercises%2Ffoundations%2F01_hello_world) and [excercise-2](https://github.com/ThePythonLedger/python-exercises/tree/main/exercises%2Ffoundations%2F02_datatypes) for better understanding. ## Assignment {#assignment} -Try the following excercise to establish your knowlege. We will build a shop, starting with defining (declaring) diffrent variables in this lesson and progress with our little shop as we go further along. +Try the following excercise to establish your knowlege. We will build a bookstore, starting with defining (declaring) diffrent variables in this lesson and progress with our little bookstore as we go further along. You will need to do this assignment on your own machine. -1. Create a new directory with the name `simple-python-shop` -2. Navigate inside the newly created directory -3. Instantiate `git` repository -4. Create a new file with the name `main.py` -5. Inside the file define the the following variables: - * `shop_name` - set its value to some **string** - * `item_name` - set its value to some **string** - * `item_quantity` - set its value to some **integer** - * `item_price` - set its value to some **float** - * `item_available` - set its value to some **boolean** -6. Output the variables you defined (using `print()` function) like the following example: +1. Create a new file with the name `main.py` +2. Inside the file define the following variables: + * `bookstore_name` - set its value to some **string** (*eg. `"Willow Creek Books"`*) + * `book_title` - set its value to some **string** (*eg. `"The Last Cartographer"`*) + * `book_quantity` - set its value to some **integer** (*eg. `3`*) + * `book_price` - set its value to some **float** (*eg. `18.5`*) + * `book_available` - set its value to some **boolean** (*eg. `True`*) +3. Output the variables you defined (using `print()` function) like the following example: ``` Shop name: Merlin Shop Item name: Excalibur @@ -179,7 +176,7 @@ You will need to do this assignment on your own machine. Item price: $67.2 Item available: True ``` -7. Make sure your program works as expected then create a repository and push your code to Github. +7. Make sure your program works as expected then create a repository and push your code to github ## Deepen Your Knowlege Go through these articles to deepen your knowlege about the topics covered in this lesson. diff --git a/curriculum/04-python-foundations/02-math-stringops-comparisons.md b/curriculum/04-python-foundations/02-math-stringops-comparisons.md index 4a8e0bb..76fb742 100644 --- a/curriculum/04-python-foundations/02-math-stringops-comparisons.md +++ b/curriculum/04-python-foundations/02-math-stringops-comparisons.md @@ -211,28 +211,42 @@ print("not True: ", not True) Try to solve [excercise-3](https://github.com/ThePythonLedger/python-exercises/tree/main/exercises%2Ffoundations%2F03_math_and_comparisons) for better understanding. ## Assignment -In the last assignment we have declared our shop variables and printed the inventory. In this one you are tasked with: -1. Open your code editor in your last project directory `simple-python-shop` +In the last assignment we have declared our bookstore variables and printed the inventory. In this one you are tasked with: + +1. Open your code editor in your last project directory `simple-bookstore` 2. Open `main.py` file we have been working on 3. Standardize your strings: - * Convert `shop_name` to **uppercase** (e.g., `MERLIN SHOP`) - * Convert item name to **titlecase** (e.g., `Excalibur`) + * Convert `bookstore_name` to **uppercase** (e.g., `WILLOW CREEK BOOKS`) + * Convert book title to **capitalised** (e.g., `The last cartographer`) 4. Calculate the checkout price: - * Create variable `total` by multiplying `item_price` and `item_quantity` + * Create variable `inventory_total` by multiplying `book_price` and `book_quantity` 5. Comparison checks: - * Create a boolean `is_large_order` that evaluates whether `item_quantity` is greater then or equal to `3`. + * Modify `book_avilable` so it evaluates whether `book_quantity` is greater than `0`. 6. Update your output to use **f-string** : ``` - Welcome to MERLIN SHOP - -------------------------------- - Item: Excalibur - Purchased: 3 x 67.20 - Total: $201.60 - Large Order: True - -------------------------------- - Thank you for your purchase ! + Welcome to inventory system for WILLOW CREEK BOOKS + - - - - - - - - - - - - - - - - - - - - + CURRENT INVENTORY + - - - - - - - - - - - - - - - - - - - - + Book: The Last Cartographer -> [price:18.5, copies: 3, available: True] + - - - - - - - - - - - - - - - - - - - - + Inventory total: 55.5 + - - - - - - - - - - - - - - - - - - - - + Thank you for using our inventory system. ``` -7. Commit your changes with `git` and push to Github. +7. Make sure your program works as expected, then: + * Check your *git* status (`git status`) + * Above command should show that your file `main.py` has changes from the last time. Just run `git commit -m "Added basic receipt"` as we already have `main.py` in our commit from before. + * Finally, `git push` to your remote repository + +:::info +While you are developing our little bookstore, most of your `git` commands will be the same in structure: +* Check status with `git status`. +* Commit changes with `git commit -m ""`. +* Push the changes to remote repository with `git push` + +From now on, we will assume you know what commands to run in order to push the changes to remote repository, so lessons will use a shorter `"Commit and push the changes"` form. +::: ## Deepen Your Knowledge 1. Learn more about [Basic math in Python](https://cs.stanford.edu/people/nick/py/python-math.html#math) from article in **Stanford University**, covering all the topics in this lesson but in a different style and a bit more. diff --git a/curriculum/04-python-foundations/03-user-input-and-conditionals.md b/curriculum/04-python-foundations/03-user-input-and-conditionals.md index 59c2976..7d5f934 100644 --- a/curriculum/04-python-foundations/03-user-input-and-conditionals.md +++ b/curriculum/04-python-foundations/03-user-input-and-conditionals.md @@ -88,22 +88,31 @@ elif age <= 15: ## Assigment Now that you know how to get user input and branch your program using conditional logic (`if`, `elif`, `else`) the code can move away from hardcoded values and become interactive. -**Goal:** use `input()` to collect user choices, cast strings to numbers, and use conditional logic to apply discounts and stock checks. - -1. Open `main.py` file in our `simple-python-shop` project directory. -2. Add a new variable `item_stock` and set it to some integer -3. Interactive input: - * Ask the user for desired `item_quantity` using `input()`. **Don't forget** to cast the string to integer ! -4. Stock & Availability Check - * If `item_quantity` is less or equal to `0` print an error message: `Invalid quantity ordered` - * If `item_quantity` is greater then `item_stock` print `Sorry, we do not have enough stock.` -5. Dynamic discount (conditionals) +1. Open `main.py` file in our `simple-bookstore` project directory. +2. Create a new variable to hold stock count + * `book_stock` - an **int**, for example `3` +3. Now the customer comes in to buy the only book we have at our bookstore, so you must: + * Ask the user (using `input()`) how many books he wants to buy and save that to `book_quantity` variable. **Do not forget** to cast **str** to **int**. +4. We need to check if the customer entered valid order and do we have that much in stock. If any of below conditions is `True` print the warning message to the user and **do not** do calculations or final print. + * `book_quantity` is less or equal to zero + * `book_quantity` is less or equal to `book_stock` +5. Customers have a discount of 10% if their `total` is over `100` * Calculate the total (you should have this from the last lesson) - * If `total` is over `100` apply a **10%** discount (`total * 0.90`) and print: `Discount applied: 10%` - * Otherwise print: `No discount applied` + * If `total` is over `100` apply a **10%** discount (`total * 0.90`) and print: `Discount applied: 10%`, otherwise print: `No discount applied` 6. Receipt Output - * Output the final receipt showing item name, quantity, applied discount state, and final amount due. -7. Commit and push your updated code to Github. + * Output the final receipt showing book title, quantity, applied discount state, and final amount due. + ``` + Welcome to WILLOW CREEK BOOKS + -------------------------------- + Book: The Last Cartographer + Purchased: 3 x 18.50 + No discount applied ! + Total: $55.50 + Bulk Order: True + -------------------------------- + Thank you for your purchase ! + ``` +7. Commit and push your changes. ## Deepen Your Knowledge * Learn more about [Indentation in Python](https://realpython.com/ref/glossary/indentation/) from this **Real Python** article diff --git a/curriculum/04-python-foundations/04-loops.md b/curriculum/04-python-foundations/04-loops.md index fbf1519..608817c 100644 --- a/curriculum/04-python-foundations/04-loops.md +++ b/curriculum/04-python-foundations/04-loops.md @@ -119,6 +119,11 @@ These statements `break` and `continue` work only in loops. If you try to use th ::: ## Assigment +1. Open `main.py` in your `simple-bookstore` project. +2. Create a new variable named `book_count` and set it to `0` as its initial value. +3. Use a `while` loop to ring up a stack of books at checkout: repeatedly prompt for the price printed on the price tag of the next book being scanned (this is a small bookstore without barcode lookup yet, so the cashier reads each tag by hand). + * If the price entered is 0, break out of the loop (no more books to scan) + * Otherwise, add the price entered to `total` and increment `book_count` by 1. 1. Open `main.py` in your `simple-python-shop` project. 2. Set `item_quantity` to `0` as its initial value and remove `item_price` variable. 3. Use a `while` loop to repeatedly prompt the user for an item price. @@ -127,7 +132,7 @@ These statements `break` and `continue` work only in loops. If you try to use th * Otherwise, check if `item_stock - item_quantity` is more than `1` and if not, break out of the loop, informing the user we are out of stock. * Otherwise, add the price user entered to `total` and increment `item_quantity` by 1. 4. When the loop finishes, determine if the `total` can have a discount and print out the final receipt. -5. Make sure your program works, then commit and push your code +5. Make sure your program works, then commit and push changes. ## Deepen Your Knowlege From 4ddac7ba78015278905aaa09f101d9aef471efa1 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Wed, 23 Sep 2026 18:28:37 +0200 Subject: [PATCH 80/81] Aligned and improved assigment in 03-user-input lesson --- .../02-math-stringops-comparisons.md | 6 +- .../03-user-input-and-conditionals.md | 62 ++++++++++++------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/curriculum/04-python-foundations/02-math-stringops-comparisons.md b/curriculum/04-python-foundations/02-math-stringops-comparisons.md index 76fb742..97b1368 100644 --- a/curriculum/04-python-foundations/02-math-stringops-comparisons.md +++ b/curriculum/04-python-foundations/02-math-stringops-comparisons.md @@ -211,7 +211,7 @@ print("not True: ", not True) Try to solve [excercise-3](https://github.com/ThePythonLedger/python-exercises/tree/main/exercises%2Ffoundations%2F03_math_and_comparisons) for better understanding. ## Assignment -In the last assignment we have declared our bookstore variables and printed the inventory. In this one you are tasked with: +In the last assignment we have declared our bookstore variables and printed the inventory. In this one you are tasked with making code more robust and logical. 1. Open your code editor in your last project directory `simple-bookstore` 2. Open `main.py` file we have been working on @@ -224,11 +224,11 @@ In the last assignment we have declared our bookstore variables and printed the * Modify `book_avilable` so it evaluates whether `book_quantity` is greater than `0`. 6. Update your output to use **f-string** : ``` - Welcome to inventory system for WILLOW CREEK BOOKS + Welcome to WILLOW CREEK BOOKS inventory system - - - - - - - - - - - - - - - - - - - - CURRENT INVENTORY - - - - - - - - - - - - - - - - - - - - - Book: The Last Cartographer -> [price:18.5, copies: 3, available: True] + - Book: The Last Cartographer -> [price:18.5, copies: 3, available: True] - - - - - - - - - - - - - - - - - - - - Inventory total: 55.5 - - - - - - - - - - - - - - - - - - - - diff --git a/curriculum/04-python-foundations/03-user-input-and-conditionals.md b/curriculum/04-python-foundations/03-user-input-and-conditionals.md index 7d5f934..9425777 100644 --- a/curriculum/04-python-foundations/03-user-input-and-conditionals.md +++ b/curriculum/04-python-foundations/03-user-input-and-conditionals.md @@ -85,34 +85,50 @@ elif age <= 15: print(f"{name} is not 15 years old") ``` +:::tip +In below assigment you are tasked with checking some rules and exiting application if any are broken. + +You can use built-in module called `sys` which has some handy functionality to work with our operating system. For now, we are only interested in using its `exit()` functions. It takes in **int** value to provide as **exit code** which other applications can use to interpret whether your program run successfully or failed and in what way. + +It is common to use `0` as **success** and any other positive integer to signify a failure. + +You can use it like this: +```python +import sys +sys.exit(0) # success +sys.exit(1) # failed / error +``` + +We will learn more about built-in, custom and third-party **modules** (called libraries) later in the course. +::: + ## Assigment -Now that you know how to get user input and branch your program using conditional logic (`if`, `elif`, `else`) the code can move away from hardcoded values and become interactive. +Now that you know how to get user input and branch your program using conditional logic the code can move away from hardcoded values and become interactive. 1. Open `main.py` file in our `simple-bookstore` project directory. -2. Create a new variable to hold stock count - * `book_stock` - an **int**, for example `3` -3. Now the customer comes in to buy the only book we have at our bookstore, so you must: - * Ask the user (using `input()`) how many books he wants to buy and save that to `book_quantity` variable. **Do not forget** to cast **str** to **int**. -4. We need to check if the customer entered valid order and do we have that much in stock. If any of below conditions is `True` print the warning message to the user and **do not** do calculations or final print. - * `book_quantity` is less or equal to zero - * `book_quantity` is less or equal to `book_stock` -5. Customers have a discount of 10% if their `total` is over `100` - * Calculate the total (you should have this from the last lesson) - * If `total` is over `100` apply a **10%** discount (`total * 0.90`) and print: `Discount applied: 10%`, otherwise print: `No discount applied` -6. Receipt Output - * Output the final receipt showing book title, quantity, applied discount state, and final amount due. +2. Instead of hardcoding values (`booktore_name`, `book_title`, `book_quantity`, `book_price`) we will ask the user to enter these values using `input()` function. **Remember** that `input()` always returns **str** so we must *cast* the string to desired type (`book_quantity` to **int** and `book_price` to **float**). Replace all of these variables hardcoded values to `input()` function, asking the user to enter the data. +3. Now the system must add some contraints, printing the error message and exiting if any of the rules are broken. Add these below each of the inputs, so that check runs as soon as user enters something. Rules are as follows: + * `bookstore_name` must be between 3 and 20 characters long + * `book_name` must be between 3 and 15 characters long + * `book_quantity` must be positive **integer** (above `0`) + * `book_price` must be positive **float** (above `0.00`) +4. System must now also calculate taxes that depend on the `book_price`, so make another variable `book_tax` and set it to `0`. Then calculate the tax using below rules, assign it to `book_tax` and print out the tax applied. + * If `book_price` is above `5` tax is `3%` (`0.03`) + * If `book_price` is above `10` tax is `5%` (`0.05`) + * If `book_price` is above `18` tax is `10%` (`0.1`) +5. Display inventory listing like this: ``` - Welcome to WILLOW CREEK BOOKS - -------------------------------- - Book: The Last Cartographer - Purchased: 3 x 18.50 - No discount applied ! - Total: $55.50 - Bulk Order: True - -------------------------------- - Thank you for your purchase ! + Welcome to WILLOW CREEK BOOKS inventory system + - - - - - - - - - - - - - - - - - - - - + CURRENT INVENTORY + - - - - - - - - - - - - - - - - - - - - + - Book: The Last Cartographer -> [price:$18.5, tax: 10%, copies: 3, available: True] + - - - - - - - - - - - - - - - - - - - - + Inventory total: $55.5 [VAT: $60.05] + - - - - - - - - - - - - - - - - - - - - + Thank you for using our inventory system. ``` -7. Commit and push your changes. +6. Commit and push your changes. ## Deepen Your Knowledge * Learn more about [Indentation in Python](https://realpython.com/ref/glossary/indentation/) from this **Real Python** article From 782bb3cc2e57bc5adcde209da037ff798b5739c5 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 5 Oct 2026 16:27:58 +0200 Subject: [PATCH 81/81] Last update to lesson assigments --- .../01-output-variable-datatypes.md | 2 +- .../03-user-input-and-conditionals.md | 6 +++-- curriculum/04-python-foundations/04-loops.md | 27 ++++++++++++++++--- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/curriculum/04-python-foundations/01-output-variable-datatypes.md b/curriculum/04-python-foundations/01-output-variable-datatypes.md index f16113f..3c02a53 100644 --- a/curriculum/04-python-foundations/01-output-variable-datatypes.md +++ b/curriculum/04-python-foundations/01-output-variable-datatypes.md @@ -176,7 +176,7 @@ You will need to do this assignment on your own machine. Item price: $67.2 Item available: True ``` -7. Make sure your program works as expected then create a repository and push your code to github +7. Make sure your program works as expected then create a repository and push your code to Github. ## Deepen Your Knowlege Go through these articles to deepen your knowlege about the topics covered in this lesson. diff --git a/curriculum/04-python-foundations/03-user-input-and-conditionals.md b/curriculum/04-python-foundations/03-user-input-and-conditionals.md index 9425777..eebfd6b 100644 --- a/curriculum/04-python-foundations/03-user-input-and-conditionals.md +++ b/curriculum/04-python-foundations/03-user-input-and-conditionals.md @@ -88,13 +88,15 @@ elif age <= 15: :::tip In below assigment you are tasked with checking some rules and exiting application if any are broken. -You can use built-in module called `sys` which has some handy functionality to work with our operating system. For now, we are only interested in using its `exit()` functions. It takes in **int** value to provide as **exit code** which other applications can use to interpret whether your program run successfully or failed and in what way. +You can use built-in module called `sys` which has some handy functionality to work with our operating system. For now, we are only interested in using its `exit()` function. It takes in **int** value to provide as **exit code** which other applications can use to interpret whether your program run successfully or failed and in what way. It is common to use `0` as **success** and any other positive integer to signify a failure. +To use other modules, you use `import` keyword, followed by the name of the module. Usually, these are located at the top of the file, before writing your logic. + You can use it like this: ```python -import sys +import sys # once at the top of the file sys.exit(0) # success sys.exit(1) # failed / error ``` diff --git a/curriculum/04-python-foundations/04-loops.md b/curriculum/04-python-foundations/04-loops.md index 608817c..bce7a18 100644 --- a/curriculum/04-python-foundations/04-loops.md +++ b/curriculum/04-python-foundations/04-loops.md @@ -114,10 +114,31 @@ for item in range(10): :::tip[Both `break` and `continue` work only in loops] -These statements `break` and `continue` work only in loops. If you try to use them outside of the loop you will encounter an error. - +These statements `break` and `continue` work only in loops. If you try to use them outside the loop you will encounter an error. ::: +## `else` In Loops +Both **for** and **while** loops have an optional condition `else` which is used when loop exits *without* hitting a break inside the loop, but the loop exits. Extremly useful and one of the less known Python feature. + +In a `for` loop, the `else` clause is executed after the loop finishes its final iteration, that is, if no break occurred. + +In a `while` loop, it’s executed after the loop’s condition becomes false. + +In either kind of loop, the `else` clause is not executed if the loop was terminated by a `break`. Of course, other ways of ending the loop early, such as a `return` or a `raised exception`, will also skip execution of the `else` clause. + +Let us see this in action: +```python interactive debug +for n in range(2, 10): + for x in range(2, n): + if n % x == 0: + print(n, 'equals', x, '*', n//x) + break + else: + # loop fell through without finding a factor + print(n, 'is a prime number') +``` +Look closely, the `else` clause belongs to the `for` loop, not `if` statement. + ## Assigment 1. Open `main.py` in your `simple-bookstore` project. 2. Create a new variable named `book_count` and set it to `0` as its initial value. @@ -134,6 +155,4 @@ These statements `break` and `continue` work only in loops. If you try to use th 4. When the loop finishes, determine if the `total` can have a discount and print out the final receipt. 5. Make sure your program works, then commit and push changes. -## Deepen Your Knowlege - ## What's Next