I'm working with Python 3.12 and recently added mypy
type-checking to my project. I've encountered an odd issue where mypy
throws a syntax error for certain f-strings in my code, specifically those with newline characters in the middle of the f-string. The curious thing is that the Python interpreter doesn’t complain at all and runs the code just fine.
Here’s a simplified example of the kind of f-string that mypy
flags as a syntax error:
name = "Alice"
message = f"Hello, {name
}, welcome!"
Mypy error:
mypy minimal_reproducible_example.py
src/loculus_preprocessing/alice.py:2: error: unterminated string literal (detected at line 2) [syntax]
Found 1 error in 1 file (errors prevented further checking)
Even adding --python-version 3.12
doesn't fix it.
I understand that using triple quotes ("""
) for multi-line strings is recommended, but in this case, the code works in the interpreter without issue, while mypy
consistently fails with a syntax error.
My questions:
mypy
consider this a syntax error, even though Python 3.12 accepts it?mypy
, or am I overlooking something in Python's syntax that could lead to issues?mypy uses the standard library's ast
module to parse Python code, so mypy can't parse Python 3.12 code (including multiline f-strings) if it's installed on Python 3.11 or below. As for why the command-line options don't help the issue, none of them actually changes the Python version used by mypy:
--python-version=3.12
: This is relevant to sys.version_info
guards so that mypy knows the correct blocks of code to analyse for code written for multiple Python versions:
import sys
if sys.version_info >= (3, 12):
# PEP 698 - only available in the standard library's `typing` module
# from Python 3.12 onwards. This block of code is only reached for analysis if:
# 1. you're actually running mypy under Python >= 3.12, or
# 2. you've added `--python-version=3.12` when running mypy on Python 3.11 and below.
from typing import override
else:
# mypy will warn you of errors here if you *don't* add
# `--python-version=3.12` and you're running mypy on Python 3.11 or below.
from typing import override # ✘ needs import from `typing_extensions`
--python-executable
: This is for discovering the virtual environment, and thus the 3rd-party packages that are available for importing when type-checking your code.
By default, mypy uses the same virtual environment as it is installed on, so things usually "just work" if you pip install mypy
.
Pointing --python-executable
to a Python 3.12 executable with a mypy installed on Python 3.11 will make mypy attempt to use Python 3.11's ast
to parse 3rd party libraries installed on the Python 3.12's virtual environment. If any of the packages have multiline f-strings, then the analysis will fail with a syntax error.