Every Python exercise on this site checks your solution twice. First it runs the tests. Then it runs a type checker called mypy. The site accepts your solution only when both pass.
Here is a function that passes its test and still fails:
def greet(name):
return "Hello, " + name
greet("Ada") returns "Hello, Ada", so a test for it passes. mypy, in
strict mode, still reports an error:
L1:1 [no-untyped-def]
Function is missing a type annotation
Add the annotations, and both checks pass:
def greet(name: str) -> str:
return "Hello, " + name
What mypy does
A type checker reads your code without running it, and checks that your
code uses each value the way its type allows. If a function says it takes a str,
mypy reports any call that passes an int. It finds this kind of bug before
the code runs, including in branches your tests never reach.
mypy is one of several type checkers for Python, and the one this site uses.
Strict mode, mypy --strict, turns on extra checks. The first one you
will meet requires every function to declare a type for each parameter and
for its return value.
Run and Submit do different things
- Run runs the visible test cases and shows which ones pass. It does not run mypy.
- Submit runs every test case, including hidden ones, and then runs
mypy --stricton your file. The result says "Accepted" only when the tests pass and mypy reports no errors.
If the tests pass and mypy does not, the result says "Not accepted. The tests passed but mypy --strict did not." Fix the errors listed under it, and submit again.
Your code runs on your own computer, not on the site's servers. The crackedai-connect runtime, which you install once, runs the tests and mypy and sends the results back to the page.
Read a mypy error
Each mypy error shows three things:
- its line and column, such as
L2:12for line 2, column 12; - an error code in square brackets, such as
[union-attr]; - a sentence that says what is wrong.
def shout(text: str | None) -> str:
return text.upper()
L2:12 [union-attr]
Item "None" of "str | None" has no attribute "upper"
str | None means the value is either a string or None. mypy is saying
that text might be None, and None has no .upper() method. Check for
None first:
def shout(text: str | None) -> str:
if text is None:
return ""
return text.upper()
After the if, mypy knows that text is a str. A check like this, which
rules out a type, is called narrowing.
The error code is the quickest way to look an error up. mypy's list of error codes explains each one with an example.
Check your understanding Your solution passes every test, but the result says "Not accepted". What do you look at first? Show answer Hide answer
Look at the mypy errors listed under the result. The tests passed, so the
logic is probably right. In strict mode, the usual cause is a missing
annotation, or code that uses a value that might be None without checking
it first. Fix each error, then submit again.
Going further
Submit runs mypy --strict --warn-unreachable --extra-checks --ignore-missing-imports. It checks your code against the oldest Python
version the exercise supports. A later article in this track lists what
--strict turns on. The next exercise has you fix the mypy errors in code
whose visible tests already pass.