Artwork by @allison_horst
đ Debugging scenarios and solutions
Quick debugging tips
- Read the error message and look at the line that it refers to.
- Sometimes the issue is at the line just above the line that was listed in the error.
- If enabled, pay close attention to the syntax highlighting in your editor, which can point at where the error might be happening.
- Use
print()
statements to display the type and value of your variable. - Go back to the instructions and carefully re-read them.
- Use Python Tutor to visualize your code.
- Use the Rubber Duck Debugging to walk yourself through the logic of your code.
- If you are having trouble with your output not matching what is expected, use an online text comparison tool, e.g. https://text-compare.com or https://contenttool.io/text-difference-checker.
Table of contents
AttributeError: '...' object has no attribute '...'
- EOF (end-of-file) Errors
EOL while scanning string literal
- Indentation Errors
IndexError: ... index out of range
KeyError: ...
with a dictionary- Name Errors
- Positional Arguments Errors
RecursionError: maximum recursion depth exceeded
- Syntax Errors
- Type Errors
TypeError: argument of type 'int' is not iterable
TypeError: argument of type 'NoneType' is not iterable
TypeError: can only concatenate str (not "int") to str
TypeError: 'list' object cannot be interpreted as an integer
TypeError: object of type '...' has no len()
TypeError: ... takes exactly one argument (... given)
TypeError: '...' not supported between instances of '...' and '...'
TypeError: unsupported operand type(s) for +: 'int' and 'list'
ValueError: invalid literal for int() with base 10
ZeroDivisionError: division by zero
- Undesirable Results
- Common autograder error messages on Gradescope
- Contribute
AttributeError: '...' object has no attribute '...'
Example errors:
AttributeError: 'int' object has no attribute 'isdigit'
AttributeError: 'list' object has no attribute 'split'
- Example erroneous code:
my_int = 42 if my_int.isdigit(): my_float = float(my_int)
- Cause: A variable of one type is trying to use a method from a different (incompatible) type.
- Check: verify the type of the object that is listed before the
.
in the.method()
call.- Either change it to the type that the method works with (see example)
- Use another method/solution that works with the original object type (e.g., for strings stored in a list, you might need to iterate through each element of a list and use
split()
on the string element
- Corrected line of code:
my_int = "42" if my_int.isdigit(): my_float = float(my_int)
EOF (end-of-file) Errors
EOFError: EOF when reading a line
- Cause:
- Python is expecting an input but there is no input to provide.
- Alternatively, there might be a missing closing parenthesis (see
SyntaxError: unexpected EOF while parsing
). - If the error is produced when using a loop, check that you do not have an infinite loop. Look closely at the loopâs conditions and verify that the loop stops, especially, in the edge cases.
- In almost all cases,
input()
should be included inside the main program, not inside the functions.
- The program instructions might be providing 1 input value, but you have an extra
input()
in your code.num_items = int(input()) item = input()
but the input is just a single number, thereâs no
item
to provide viainput()
. - An infinite loop example -
num_items
doesnât get updated within the loop, so the condition stays alwaysTrue
(unlessnum_items == 0
and the loop is not executed):num_items = int(input()) items = [] while num_items: item = input("Enter an item: ") items.append(item)
SyntaxError: unexpected EOF while parsing
- Cause: Missing a closing parenthesis
)
. - Example erroneous code:
print('Hello, World'
- Corrected line of code:
print("Hello, World")
EOL while scanning string literal
- Cause: Missing a closing quotation mark or a mismatched quotation mark (incorrectly placed quotation can also cause it).
- Example erroneous code:
print('Hello, World) # missing a quotation mark
or
print('Hello, World") # mismatched quotation marks
Indentation Errors
IndentationError: unexpected indent
- Example erroneous code:
print("Hello world!") print("What a nice day!")
- Cause: The code is either indented even though it is not necessary or is missing an indentation. The line number in the error points at where the mismatch happened.
- Correct code:
print("Hello world!") print("What a nice day!")
IndentationError: expected an indented block
- Example erroneous code:
def print_hello(): """Print a simple greeting.""" print("Hello!")
- Cause: This error occurs if the previous line ended with a colon
:
and did not have a properly indented line of code underneath it. It is likely that the issue occured at the line directly above the line reported in the error. - Correct code (notice the indentation after the line that ends with a colon):
def print_hello(): """Print a simple greeting.""" print("Hello!")
IndexError: ... index out of range
Example errors:
IndexError: string index out of range
IndexError: list index out of range
- Example code that causes the error:
my_str = ""
print("The first symbol is", my_str[0])
print("The last symbol is", my_str[-1])
- Cause: The string/list is being indexed at a location that does not exist.
Check: Print the length of the string/list to check its maximum index (remember that Python indexing starts at 0).
- Correct code that wonât cause the error:
my_str = ""
if len(my_str) != 0: # my_str != ""
print("The first symbol is", my_str[0])
print("The last symbol is", my_str[-1])
KeyError: ...
with a dictionary
This error occurs when working with dictionaries. The line above the error shows which line caused the incorrect retrieval.
- Example erroneous code:
month_names = {
"1": "January",
"2": "February",
}
print("First month is", month_names[1]) # KeyError: 1
Alternatively, you wouldnât get an error but would get an undesired output that displays None
if using .get()
:
print("First month is", month_names.get(1)) # results in "First month is None"
- Cause: This error occurrs when trying to retrieve a value using a key that doesnât exist in the dictionary. Possible causes:
- the dictionary does not store the correct key-value pairs (did you add all necessary items? what about the edge cases?)
- the key is stored / retrieved as an incorrect type (see the example)
- Correct code (alternative options):
...
print("First month is", month_names["1"])
print("First month is", month_names.get("1"))
print("First month is", month_names[str(1)])
Name Errors
NameError: name '...' is not defined
Python would replace the ellipsis ...
with the name of the variable that itâs unable to find.
- Cause: Generally, this error happens when a function name or a variable name
- is misspelled
- has not been properly defined first
For example:
NameError: name 'Print' is not defined
- Example erroneous code:
Print('Hello, World')
- Cause: In this case, the function name is âmisspelledâ - an accidentally capitalized name of the function makes Python look for a variable called
Print
.
This error can also be caused if there is a single word (or comma-separated words) inside the print()
that needed to be displayed as the literal text but does not include quotation marks around it (similar to the SyntaxError: invalid syntax
).
- Example erroneous code:
print(Hello) print(Hello, World)
generates the same error (
NameError: name 'Hello' is not defined
), since Python is now looking for a variable calledHello
- it doesnât know that we just forgot to put quotation marks around the text.
NameError
with a dictionary
NameError: name 'A' is not defined
- Example erroneous code:
dict1 = {"A":1, "B":2, "C":3} print(dict1[A])
Cause: Missing quotation marks (
" "
) when indexing a key from the dictionary.- Correct code:
dict1 = {"A":1, "B":2, "C":3} print(dict1["A"])
Positional Arguments Errors
Letâs first look at the case where too many arguments were provided in the function call. In that case, the error would be something like: print_name takes 0 positional arguments but 1 was given
.
- Example erroneous code:
def print_name():
print("Sam")
if __name__ == '__main__':
print_name("Sam")
Cause: The function
print_name()
does not take any parameters but when calling the function one parameter is being passed. This error signifies that there is a mismatch between the number of parameteres in the function defintion and the number of arguments in the function call.Correct code:
def print_name():
print("Sam")
if __name__ == '__main__':
print_name()
This also works the other way around if you are missing arguments in the function call. For example, the function below results in an error: get_largest() missing 1 required positional argument: 'y'
.
- Example erroneous code:
def get_largest(x, y):
return max(x, y)
if __name__ == '__main__':
x = int(input())
y = int(input())
print(get_largest((x, y)))
- Cause: The function
get_largest()
takes in two parameters but when calling the function only one is passed in (i.e., a tuple with two elements). This error likewise signifies that there is a mismatch between the number of parameteres in the function defintion and the number of arguments in the function call. - Correct code:
def get_largest(x, y):
return max(x, y)
if __name__ == '__main__':
x = int(input())
y = int(input())
print(get_largest(x, y))
RecursionError: maximum recursion depth exceeded
- Cause: This error usually occurs due to an infinite recursion, which typically happens when there is âŚ
- no base case
- an invalid base case
- a missing base case
- an incorrect recursive call
- a missing
return
- Check: The following actions suggest what you can check when debugging an infinite recursion - make sure to add
print()
statements to each branch, so that you can trace which case is being called and with which arguments. Check the cases in the provided order:- No base case:
- does the recursive function definition contain an
if
statement that compares if the input parameter is a specific value, which corresponds to the base case? - do the instructions mention any specific value that can be turned into a base case? what action needs to happen in that case?
- Common base cases are typically: an empty list/string; a count/length of 0 or 1; a minimum/maximum allowed value;
- does the recursive function definition contain an
- An invalid base case: does the
if
statement compare the input parameter to the correct value of the correct type? - A missing base case:
- does there need to be another
if
/elif
statement that should check if the input parameter corresponds to an additional correct value of the correct type (remember the Fibbonacchi numbers example)? - Ask yourself: is there another case when the function does not need to do any computation/processing (so that it can easily produce the answer)? what action needs to happen in that case?
- Common additional base cases: finding a match in a list/string; a single-element list/string
- does there need to be another
- An incorrect recursive call:
- are the arguments in the recursive function call (within the function itself) being reduced / increased so that they get closer to the value in the base case? (use
print()
to verify/visualize their values) - Plug-in the next simplest case that would occur immediately after the base case and check whether the recursive call correctly triggers the base case (e.g., if the base case is an empty list, check if the function call with a single-element list would end up calling the base case).
- Check the instructions - are the input values supposed to be from a specific range (e.g., non-negative? is 0 included? are letters/strings accepted?)
- are the arguments in the recursive function call (within the function itself) being reduced / increased so that they get closer to the value in the base case? (use
- A missing
return
: Verify that if the function is supposed to return its result, then each branch contains thereturn
keyword. In the recursive case/branch, it is common toreturn
the result of calling the recursive function (i.e., the recursive call).
- No base case:
Example erroneous code illustrating the above recursion issues
Starting from the first case, we illustrate the potential issues by building on the first example:
- No base case
def fib(n):
"""
param: n (int) - the ordinal value of the Fibonacchi
sequence; expected to be > 0.
The function recursively computes the n-th Fibonacchi
number, starting from the 1st one.
returns: the computed Fibonacchi value (int)
"""
# missing a base case here - no `if` branch
return fib(n - 1) + fib(n - 2)
if __name__ == "__main__":
print(fib(3))
- An invalid base case
def fib(n):
"""
param: n (int) - the ordinal value of the Fibonacchi
sequence; expected to be > 0.
The function recursively computes the n-th Fibonacchi
number, starting from the 1st one.
returns: the computed Fibonacchi value (int)
"""
if n == '1': # incorrect type of the base case
return 1
return fib(n - 1) + fib(n - 2)
if __name__ == "__main__":
print(fib(3))
- A missing base case
def fib(n):
"""
param: n (int) - the ordinal value of the Fibonacchi
sequence; expected to be > 0.
The function recursively computes the n-th Fibonacchi
number, starting from the 1st one.
returns: the computed Fibonacchi value (int)
"""
if n == 1: # correct type of the base case
return 1 # correct return, correct value, correct type
# need another base case, for the 2nd Fibonacchi n
return fib(n - 1) + fib(n - 2)
if __name__ == "__main__":
print(fib(3))
- An incorrect recursive call
def fib(n):
"""
param: n (int) - the ordinal value of the Fibonacchi
sequence; expected to be > 0.
The function recursively computes the n-th Fibonacchi
number, starting from the 1st one.
returns: the computed Fibonacchi value (int)
"""
if n == 1:
return 1
if n == 2:
return 1
return fib(n) + fib(n - 2) # the first function call doesn't decrement n
if __name__ == "__main__":
print(fib(3))
print(fib(0)) # also, the function call is not supposed to work for n <= 0
- A missing
return
def fib(n):
"""
param: n (int) - the ordinal value of the Fibonacchi
sequence; expected to be > 0.
The function recursively computes the n-th Fibonacchi
number, starting from the 1st one.
returns: the computed Fibonacchi value (int)
"""
if n == 1:
print ( 1 ) # missing a correct return
if n == 2:
print( 1 ) # incorrect return value
return fib(n - 1) + fib(n - 2)
if __name__ == "__main__":
print(fib(3))
Syntax Errors
SyntaxError: invalid character in identifier
Cause: Either quotations around the text or some other symbol is not from the standard Latin alphabet used by Python. The error typically occurs when writing code in a text processor (e.g., Word), typing on a mobile device that has autocorrect enabled, or (rarely) when accidentally switching the keyboard language layout.
Example erroneous code:
print(âHello!â) # invalid quotations
SyntaxError: invalid syntax
This is a general error that occurs when the syntax is not correct and a âPython sentenceâ is broken. If enabled, pay close attention to the syntax highlighting, which can point at where the error might be happening.
Below are sample Python syntax rules:
- A function call must start and end with a parenthesis; the number of open and closed parentheses must match.
- The literal text has to be enclosed within the quotation marks.
- Variables must first be defined (created) before being used.
- Cause: Missing opening quotation mark or opening parenthesis or quotations around the text.
- Example erroneous code:
print(Hello World') print'Hello World print(Hello World) # see also NameError
SyntaxError: unmatched ')'
- Cause: an extra closing parenthesis
)
that does not have a matching opening paren(
. - Example erroneous code:
print('Hello, World'))
Type Errors
TypeError: argument of type 'int' is not iterable
Related error: TypeError: 'list' object cannot be interpreted as an integer
- Example erroneous code:
total = 42
sum(total)
# another alternative that would case such error
for i in total: # `in` requires a range/collection, not an integer
print(i)
- Cause: The error usually occurs when a built-in Python function that is intended for a sequence/collection is applied to an integer instead.
Check: Take a look at the line that is causing an error and verify that you are using a proper collection (i.e., a list or a range).
- Correct code:
total = [42]
sum(total)
for i in total: # `in` requires a range/collection, not an integer
print(i)
# alternatively, if `total` needed to stay as an integer
total = 42
for i in range(total):
print(i)
TypeError: argument of type 'NoneType' is not iterable
- Example erroneous code:
val = None
if "a" in val:
print("Found it!")
- Cause: The error usually occurs when the
in
operator in trying to index aNone
value instead of the sequence/collection.- Check the type/value of the object that is used after the
in
operator - if that object is a result of the functionâs return value, verify that the function is returning the correct object or that yourif
branches are set up correctly to not try to index aNone
. - Do not store the result of
print()
and attempt to index it. Just like the methods that modify lists directly (since lists are mutable),print()
does not return anything other thanNone
.
- Check the type/value of the object that is used after the
- Correct code:
val = None
if val != None:
if "a" in val:
print("Found it!")
or
val = "aeou" # correct object provided
if "a" in val:
print("Found it!")
TypeError: can only concatenate str (not "int") to str
- Example erroneous code:
num = 6
print("I would like " + num + " tacos please.")
Cause: You can only concatenate a string with a string, not a numeric type. Check the types of the variables that you are using in the concatenation.
Correct code and alternatives:
num = 6
print("I would like " + str(num) + " tacos please.") # proper string concatenation
print("I would like", num, "tacos please.") # using print defaults
print(f"I would like {num} tacos please.") # using f-strings
TypeError: 'list' object cannot be interpreted as an integer
- Example erroneous code:
total = [42]
for i in range(total):
print(i)
- Cause: The
range()
function requires an integer argument but a list is given instead. - Check:
- Is the current argument given to the
range()
supposed to be a list? Are you trying to print its values? If so, why do you need to use arange()
, which helps print indices? - Do you need to print indices of a list? If so, do you have
len()
of a list as an input to therange()
? Do you need to generate a bunch of numbers and you accidentally stored the total as a list, instead of as an integer?
- Depending on what you need to do, the potential solutions to the above error could be:
# `total` needs to be an integer, not a list
total = 42
for i in range(total):
print(i) # prints the numbers from 0 to 42 (value in total)
# or, alternatively
# `total` stays as a list but
# the range() needs to be provided a proper integer, e.g., the length of the list
total = [42]
for i in range(len(total)):
print(i) # prints the indices of the list, which is just 0
TypeError: object of type '...' has no len()
Examples include the errors
TypeError: object of type 'int' has no len()
TypeError: object of type 'float' has no len()
- Example erroneous code:
len(42)
Cause: The error usually occurs when you think that you are asking for a length of a collection (e.g., a list, string, dictionary) but in reality the argument is an integer. Examine the value that is being provided as an argument into the
len()
function.Correct code:
len([42])
TypeError: ... takes exactly one argument (... given)
Some examples of this error:
TypeError: len() takes exactly one argument (2 given)
- Example erroneous code:
len(42, 33)
- Cause: The error usually occurs when
- a built-in Python function is being applied to an incorrect object.
- the function is not given the required number of arguments.
- Correct code:
len([42, 33])
TypeError: '...' not supported between instances of '...' and '...'
Some specific instances of this error:
TypeError: '<=' not supported between instances of 'int' and 'str'
TypeError: '<' not supported between instances of 'str' and 'int'
Similar error: TypeError: unsupported operand type(s) ...
- Causes: The code is trying to compare incompatible types. The listed types are on the left and ithe right side of the provided operator respectively.
Check: Does either or both of the operands need to be converted into a numeric type?
- Erroneous code:
my_var = input() if my_var < 5: print(my_var)
- Correct code:
my_var = int(input())
if my_var < 5:
print(my_var)
TypeError: unsupported operand type(s) for +: 'int' and 'list'
Similar error: TypeError: '...' not supported between instances of 'int' and 'str'
- Example erroneous code:
nested_list = [[5, 10, 6], [7, 8, 9]]
total_sum = sum(nested_list)
Cause: The error can occur when trying to apply a built-in Python method to an unsupported type, e.g., to sum up a nested list, instead of its individual elements.
Correct code:
nested_list = [[5, 10, 6], [7, 8, 9]]
total_sum = 0
for item in nested_list:
item_sum = sum(item)
total_sum += item_sum
ValueError: invalid literal for int() with base 10
- Example erroneous code:
current_year = '1792.99' current_year = int(current_year) print(current_year)
Cause: Float, represented as a string, cannot be directly converted into an integer. If you do want to pass a string representation of a float to an int, you need to convert to a float first, then to an integer.
- Correct code:
current_year = '1792.99' current_year = float(current_year) current_year = int(current_year) print(current_year)
ZeroDivisionError: division by zero
- Example erroneous code:
print(1 / 0) # or my_list = [] print("The average value of the list is", sum(my_list) / len(my_list))
Cause: The denominator in a division is 0.
- Correct code:
my_list = [] if my_list != []: # len(my_list) != 0 print("The average value of the list is", sum(my_list) / len(my_list))
Undesirable Results
Output printing None
None
is printed even though you donât want it to be there- Example erroneous code:
def print_hello():
print("hello")
if __name__ == '__main__':
print(print_hello())
- Cause: The function
print_hello()
does not return anything (it has noreturn
statement) so when you callprint(print_hello())
you are printing its return value which isNone
. - Correct code:
def print_hello():
print("hello")
if __name__ == '__main__':
print_hello()
Function returns None but a different value is needed
- Example erroneous code:
def get_hello():
print("hello")
if __name__ == '__main__':
print(get_hello())
- Cause: The function
get_hello()
does not return anything (it has noreturn
statement) so when you callprint(get_hello())
you are printing its return value which isNone
. - Check: Sometimes, this behavior can occur when your code has nested
if
/elif
branches, which contain areturn
inside of them. If one or more of the conditions are not set up correctly, the correct return statement would not be triggered.- Verify the accuracy of the conditions, check the edge cases, especially with the
==
(e.g., is it supposed to be<
or<=
). - Note what condition needs to fail for your code to return
None
. - Debug your code by adding print statements and/or add an
else: return 42
to see which branches get executed/skipped.
- Verify the accuracy of the conditions, check the edge cases, especially with the
- Correct code:
def get_hello():
return "hello"
if __name__ == '__main__':
print(get_hello())
assert get_hello() == "hello" # to check the return value
Logic Errors
- Sometimes, we get a logic error, when the output does not match what we expect.
- Example erroneous code:
def get_largest(x,y): if x > y: return y else: return x
Cause: Although the syntax of this function is correct and the function will produce no errors, the result will be incorrect. This is simply due to a logical error - an incorrect value is being returned (or, the
if
condition needs to be changed).- Correct code:
def get_largest(x,y): if x > y: return x else: return y
Function address is printed <function function_name at 0x....>
- Function Address gets printed -
<function function_name at 0x....>
- Example erroneous code:
def area(radius):
return 3.14 * radius**2
if __name__ == '__main__':
radius = float(input())
print(f"Circle has area {area} inches squared.")
- Cause: Instead of the function call, which requires the parentheses (and the arguments, if necessary), only the name of the function is used.
- Correct code:
... print(f"Circle has area {area(radius)} inches squared.")
Common autograder error messages on Gradescope
Your submission timed out. It took longer than 600 seconds to run.
- Cause: you have an infinite
while
loop in your code. - Check: Carefully look at the condition in the
while
and ask when/if it will ever become False. Check when/where you are updating variables in the condition - the loop will keep going until the condition becomes False, so if the variable is not updated within the loop, you get an infinite loop.
Test Failed: Check the name of your .py file: it is incorrect.
- Cause: you did not name your file according to the instructions.
- We do not re-upload studentsâ files: if you would want to manually do something for all 280+ students in the class, please do not ask us to do it.
Test Failed: Syntax error when importing ...
- Cause: Something in your file is causing a syntax error (could be as simple as incorrect indentation; see the SyntaxError examples listed above).
- Check: Run your code and examine the line that is causing an error. If you are not getting any syntax errors when running code in your IDE, then verify that you have a correctly-placed
if __name__ == '__main__'
block in your file.
Contribute
If you would like to contribute another error or help us improve examples or explanations (or remove typos! :-)), you can do so by submitting a Pull Request (PR) via this repo or by submitting an Issue there.
Below are the steps for how to contribute using the GitHub interface.
Prerequisites
- Create an account on https://github.com/
- Look up how to format text using Markdown (https://www.markdownguide.org/cheat-sheet/)
- Format the error and the exampe using Markdown - you can save them as a regular txt file.
Fork this repo
This course website lives in a GitHub repository, which has a name corresponding to this quarter.
Weâll be referring to this courseâs website as the PROJECT_REPO
(https://github.com/ucsb-csw8/w23c) and the repository name as the INITIAL_REPO_NAME
.
Fork the PROJECT_REPO
using the GitHub interface - use the âForkâ button in the upper-right corner of the repo.
- Follow the instructions on the screen.
- We recommend adding
csw8-
as a prefix to the name of the repo to help you distinguish it in the list of your repositories.
Note that the forked repo will produce a different URL (i.e., link / web address) for each person who forked this repo. We will refer to it as a PROJECT_REPO_FORK
.
The PROJECT_REPO_FORK
URL will likely look like:
https://github.com/YOUR_USER_NAME/csw8-INITIAL_REPO_NAME
Make the changes
You will need to make the changes to your fork (i.e., your PROJECT_REPO_FORK
).
Step 1: Navigate to your fork
In the browser, open up the PROJECT_REPO_FORK
. (Note that you need to open your fork, not the original course repo.)
- You were navigated there automatically, when you forked the repo.
- Verify that in the top left corner, underneath the search bar, you see the name of your
PROJECT_REPO_FORK
with a forked from ucsb-csw8/w23c right underneath it.
Step 2: Edit the file
- Navigate to the
ref/
folder. - Find
debug.md
and click on it. - When the file opens up, you should see the âEdit this fileâ pencil icon âď¸ (next to the âDelete this fileâ trash icon).
- GitHub will open its file editor where you can now add your edits. Use the template provided below if you are contributing an error we have not yet listed.
- Remember to âCommit changesâ to save your work.
Template
We attempt to alphabetize the errors, so please add the new entries to their appropriate location in the file.
# `Error: ...`
This is a template for the error entries.
* Example erroneous code:
```py
#code
```
* **Cause**: ...
* **Check**: ...
* Correct code:
```py
#code
```
[Back to top](#top)
---
You are now ready to submit a Pull Request (PR) via the GitHub web interface.
Submit a Pull Request (PR)
In order for your changes to be added to the main PROJECT_REPO
, you need to issue a Pull Request (usually abbreviated as PR).
Pull Requests (PRs) are typically issued through the GitHub web interface.
- After committing your changes, click on the âPull Requestsâ tab at the top (the second link after âCodeâ in your
PROJECT_FORK_REPO
page on GitHub). - Click on the green âNew Pull Requestâ button.
Important: if you are not seeing your changes below, make sure to select the âcompare across forks
â link and then set the base
and head
repositories and branches accordingly.
base
repository should be thePROJECT_REPO
head
repository should be thePROJECT_REPO_FORK
Click on the green âCreate pull requestâ button, add a short description and an optional comment.
- Do not uncheck the box â
Allow edits by maintainers
- Finish your PR by clicking on the green âCreate Pull Requestâ button.
Congratulations! đ
We are looking forward to reviewing your contributions.
Acknowledgement
Developed by Yekaterina Kharitonova with assistance from students and course mentors.
Special thanks to Liu Kurafeeva for creating the initial formatting of this page.