Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(curriculum): improve tests and instructions for Expense Tracker project #54624

Merged
merged 16 commits into from
May 23, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -63,128 +63,132 @@
"title": "Step 13"
},
{
"id": "658238f7604f154ea9a23e1e",
"id": "66314f2add0a8b57da5d6d91",
"title": "Step 14"
},
{
"id": "65823b0167fd894f4a7ea60a",
"id": "658238f7604f154ea9a23e1e",
"title": "Step 15"
},
{
"id": "65823bbbdb4eaa4f9d20a0fb",
"id": "65823b0167fd894f4a7ea60a",
"title": "Step 16"
},
{
"id": "65823cfc74aa564ffc460489",
"id": "65823bbbdb4eaa4f9d20a0fb",
"title": "Step 17"
},
{
"id": "65823dde36392f505a39f7c7",
"id": "65823cfc74aa564ffc460489",
"title": "Step 18"
},
{
"id": "65823e87c9741750a22085a7",
"id": "65823dde36392f505a39f7c7",
"title": "Step 19"
},
{
"id": "65823ff0d4b991510fade1a8",
"id": "65823e87c9741750a22085a7",
"title": "Step 20"
},
{
"id": "65824111a09164518320088d",
"id": "65823ff0d4b991510fade1a8",
"title": "Step 21"
},
{
"id": "658244fdf4b0265334711664",
"id": "65824111a09164518320088d",
"title": "Step 22"
},
{
"id": "65824561f3478e5371a33ae5",
"id": "658244fdf4b0265334711664",
"title": "Step 23"
},
{
"id": "658246c28575d653d1f89b59",
"id": "65824561f3478e5371a33ae5",
"title": "Step 24"
},
{
"id": "65824872894f59546e3084e2",
"id": "658246c28575d653d1f89b59",
"title": "Step 25"
},
{
"id": "65824a1b16631c54fa524154",
"id": "65824872894f59546e3084e2",
"title": "Step 26"
},
{
"id": "65824c7b4e2da85597693dcf",
"id": "65824a1b16631c54fa524154",
"title": "Step 27"
},
{
"id": "65824dfdb6815d563b2d3256",
"id": "65824c7b4e2da85597693dcf",
"title": "Step 28"
},
{
"id": "6582507654b3ed5712341382",
"id": "65824dfdb6815d563b2d3256",
"title": "Step 29"
},
{
"id": "658252f6b1526d57b103d48a",
"id": "6582507654b3ed5712341382",
"title": "Step 30"
},
{
"id": "658254db6e12485a48130f57",
"id": "658252f6b1526d57b103d48a",
"title": "Step 31"
},
{
"id": "658255d5f955175b270f251d",
"id": "658254db6e12485a48130f57",
"title": "Step 32"
},
{
"id": "6582575b8089f85b8b92d7c8",
"id": "658255d5f955175b270f251d",
"title": "Step 33"
},
{
"id": "658258c0e5fbe85c14c060cf",
"id": "6582575b8089f85b8b92d7c8",
"title": "Step 34"
},
{
"id": "65825a9520a0795c8afbef50",
"id": "658258c0e5fbe85c14c060cf",
"title": "Step 35"
},
{
"id": "65825b758fe85a5cebabc8c5",
"id": "65825a9520a0795c8afbef50",
"title": "Step 36"
},
{
"id": "65825cda2668995d5168e37c",
"id": "65825b758fe85a5cebabc8c5",
"title": "Step 37"
},
{
"id": "65825e96b5db5f5dee6bf57c",
"id": "65825cda2668995d5168e37c",
"title": "Step 38"
},
{
"id": "6582601b2987045e8e7da994",
"id": "65825e96b5db5f5dee6bf57c",
"title": "Step 39"
},
{
"id": "6582622cb6c11a5f4c5d79b4",
"id": "6582601b2987045e8e7da994",
"title": "Step 40"
},
{
"id": "6582687859366a618424d84b",
"id": "6582622cb6c11a5f4c5d79b4",
"title": "Step 41"
},
{
"id": "65826a6e9d189a623141c726",
"id": "6582687859366a618424d84b",
"title": "Step 42"
},
{
"id": "65826af5b226a5628aa154b1",
"id": "65826a6e9d189a623141c726",
"title": "Step 43"
},
{
"id": "65826befd75db5632bd73df6",
"id": "65826af5b226a5628aa154b1",
"title": "Step 44"
},
{
"id": "65826befd75db5632bd73df6",
"title": "Step 45"
}
],
"helpCategory": "Python"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Start by defining a function named `add_expense` that takes three parameters: `e

# --hints--

You should declare a function named `add_expense`.
You should use the `def` keyword to declare a function named `add_expense`.

```js
({ test: () => assert(runPython(`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ dashedName: step-2

# --description--

A list in Python is a built-in data type that allows you to store many items in a single data structure. In Python, you create a list by putting items inside square brackets `[]`, with each item separated from the following one by a comma.
A list in Python is a built-in data type that allows you to store many items in a single data structure. In Python, you create a list by putting items inside square brackets (`[]`), with each item separated from the following one by a comma.

```py
numbers = [1, 2, 3, 4]
```

Create an empty list named `expenses`. You will use it to store each of your expenses.
Use a pair of square brackets to create an empty list named `expenses`. You will use it to store each of your expenses.

# --hints--

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,29 @@ dashedName: step-3

# --description--

The `expenses` parameter of your `add_expense` function will be a list of expenses. You want to be able to add items at the end of your list. For that you can use the `.append()` list method:
The `expenses` parameter of your `add_expense` function will be a list of expenses. You want to be able to add items at the end of your list. For that you'll use the `.append()` list method:

```py
my_list = [2, 4, 7]
my_list.append(3)
```

In the example above, after appending `3`, `my_list` would be `[2, 4, 7, 3]`. Replace `pass` with a call to the `.append()` method on the `expenses` list. Don't pass any arguments to `.append()` for now.
In the example above, after appending `3`, `my_list` would be `[2, 4, 7, 3]`.

Replace `pass` with a call to the `.append()` method on the `expenses` list. Don't pass any arguments to `.append()` for now.

# --hints--

You should have `expenses.append()` in your function.

```js
assert.match(code, /^\s+expenses\.append\s*\(\s*\)/m)
({ test: () => assert(runPython(`_Node(_code).find_function("add_expense").has_stmt("expenses.append()")`)) })
```

You should not have `pass` in your function.

```js
({ test: () => assert.isFalse(runPython(`_Node(_code).find_function("add_expense").has_pass()`)) })
```

# --seed--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ dashedName: step-4

# --description--

A dictionary is another built-in data type in Python. A dictionary is a collection of data in the form of *key*-*value* pairs. Dictionaries are defined with curly braces `{}` and they contain key-value pairs separated by commas. Each key is followed by a colon `:` and the value:
A dictionary is another built-in data type in Python. A dictionary is a collection of data in the form of *key*-*value* pairs. Dictionaries are defined with curly braces (`{}`) and they contain key-value pairs separated by commas. Each key is followed by a colon (`:`) and the value:

```py
{'amount': 50.0, 'category': 'Food'}
Expand All @@ -19,10 +19,20 @@ Create a dictionary with a key `'amount'` and value of the `amount` parameter an

# --hints--

You should have `expenses.append({'amount': amount})` in your function.
You should pass a dictionary as the argument to the `.append()` method.

```js
assert.match(code, /^\s+expenses\.append\s*\(\s*\{\s*("|')amount\1\s*:\s*amount\s*\}\s*\)/m)
({ test: () => assert(runPython(`
import ast
node = _Node(_code).find_function("add_expense").find_calls("append")[0].find_call_args()
len(node) == 1 and isinstance(node[0].tree, ast.Dict)
`)) })
```

You should pass `{'amount': amount}` as the argument to the `.append()` method.

```js
({ test: () => assert(runPython(`_Node(_code).find_function("add_expense").has_stmt("expenses.append({'amount': amount})")`)) })
```

# --seed--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,20 @@ Add another key-value pair to the dictionary you are appending to the `expense`

# --hints--

You should have `expenses.append({'amount': amount, 'category': category})` in your code.
You should add a second key-value pair to the dictionary you are passing as the argument to the `.append()` method.

```js
assert.match(code, /^\s+expenses\.append\s*\(\s*\{\s*("|')amount\1\s*:\s*amount\s*,\s*("|')category\2\s*:\s*category\s*\}\s*\)/m)
({ test: () => assert(runPython(`
import ast
node = _Node(_code).find_function("add_expense").find_calls("append")[0].find_call_args()
len(node) == 1 and isinstance(node[0].tree, ast.Dict) and len(node[0].tree.keys) == 2
`)) })
```

You should pass `{'amount': amount, 'category': category}` as the argument to the `.append()` method.

```js
({ test: () => assert(runPython(`_Node(_code).find_function("add_expense").has_stmt("expenses.append({'amount': amount, 'category': category})")`)) })
```

# --seed--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ dashedName: step-6

# --description--

Start by defining a function named `print_expenses` that takes one parameter `expenses`. This function will later be used to display each expense in your list.
Next, define a function named `print_expenses` that takes one parameter `expenses`. This function will later be used to display each expense in your list.

Fill the body of your new function with a `pass` statement.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,22 @@ Inside the `print_expenses` function, create a `for` loop that iterates over eac

# --hints--

You should have `for expense in expenses:` in your `print_expenses` function. Remember to use `pass` within the loop body.
You should create a `for` loop that iterates over `expenses` in your `print_expenses` function. Remember to use `pass` within the loop body.

```js
({ test: () => assert.match(code, /for\s+expense\s+in\s+expenses\s*:/ ) })
({ test: () => assert(runPython(`_Node(_code).find_function("print_expenses").find_for_loops()[0].find_for_iter().is_equivalent("expenses")`)) })
```

You should use `expense` as the loop variable.

```js
({ test: () => assert(runPython(`_Node(_code).find_function("print_expenses").find_for_loops()[0].find_for_vars().is_equivalent("expense")`)) })
```

You should have `pass` only inside your loop body.

```js
({ test: () => assert.isFalse(runPython(`_Node(_code).find_function("print_expenses").has_pass()`)) })
```

# --seed--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@ dashedName: step-8

Next, you are going to display the details for each expense.

Inside the `for` loop, replace `pass` with a `print()` call and pass it the following f-string: `f'Amount: {expense}, Category: {expense}'`. Leave the placeholders empty for now.
Inside the `for` loop, replace `pass` with a `print()` call and pass it the following f-string: `f'Amount: {expense}, Category: {expense}'`.

# --hints--

You should have `print(f'Amount: {expense}, Category: {expense}')` in your `for` loop.
You should print `f'Amount: {expense}, Category: {expense}'` in your `for` loop.

```js
({ test: () => assert.match(code, /^\s+print\s*\(\s*f("|')Amount: \{\s*expense\s*\}, Category: \{\s*expense\s*\}\1\s*\)/m) })
({ test: () => assert(runPython(`_Node(_code).find_function("print_expenses").find_for_loops()[0].has_call("print(f'Amount: {expense}, Category: {expense}')")`)) })
```

You should not have `pass` inside your loop body.

```js
({ test: () => assert.isFalse(runPython(`_Node(_code).find_function("print_expenses").find_for_loops()[0].find_bodies()[0].has_pass()`)) })
```

# --seed--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ dashedName: step-9

# --description--

You can access values in a dictionary through its keys. You need to use the bracket notation and include the key between the square brackets:
In Python, an important thing to know is that the same type of quote used to define a string cannot be used inside it. For example, the string `'I'm a string!'` is not valid. To use the single quote inside that string you should either:

- Escape the quote by prepending a backlash to it: `'I\'m a string!'`
- Or use double quotes to define the string: `"I'm a string!"` (preferred).

You can access values in a dictionary through its keys. You need to use bracket notation and include the key between the square brackets:

```py
my_dict = {'amount': 50.0, 'category': 'Food'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ dashedName: step-10

# --description--

You will need a function to calculate the total amount of expenses. Define a function named `total_expenses` that takes one parameter `expenses`. Fill the function body with a `pass` statement for now.
You will need a function to calculate the total amount of expenses.

Define a function named `total_expenses` that takes one parameter `expenses`. Fill the function body with a `pass` statement for now.

# --hints--

Expand All @@ -21,7 +23,7 @@ You should define a function named `total_expenses`.
})
```

Your`total_expenses` function should take a single `expenses` parameter.
Your `total_expenses` function should take a single `expenses` parameter.

```js
({ test: () => assert(runPython(`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,22 @@ Lambda functions are brief, anonymous functions in Python, ideal for simple, one
lambda x: expr
```

In the example above, `x` is a parameter to be used in the expression `expr`. Create a `test` variable and assign it a lambda function that takes an `x` parameter and returns `x * 2`.
In the example above, `x` represents a parameter to be used in the expression `expr`, and it acts just like any parameter in a traditional function. `expr` is the expression that gets evaluated and returned when the lambda function is called.

Create a variable named `test` and assign it a lambda function that takes an `x` parameter and returns `x * 2`.

# --hints--

You should have `test = lambda x: x * 2` in your code.
You should declare a variable named `test`.

```js
({ test: () => assert(runPython(`_Node(_code).has_variable("test")`))})
```

You should assign `lambda x: x * 2` to your `test` variable.

```js
({ test: () => assert.match(code,/^test\s*=\s*lambda\s+x\s*:\s*x\s*\*\s*2/m)})
({ test: () => assert(runPython(`_Node(_code).find_variable("test").is_equivalent("test = lambda x: x * 2")`))})
```

# --seed--
Expand Down