Repository: python/mypy (Python)

Issue:
Friendlier error when 3.10 is parsed as float in pyproject.toml
**Bug Report**

<!--
Note: If the problem you are reporting is about a specific library function, then the typeshed tracker is better suited
for this report: https://github.com/python/typeshed/issues
-->

Running mypy with Python 3.10 and `python_version` in the config file has a few wrong behaviors:
1. It lists mypy must be 3.4 or higher (it should say 3.6)
2. It truncates Python 3.10 to 3.1
3. It outputs a message when there shouldn't be one (you can invoke mypy with Python 3.10)

**To Reproduce**

Here is a subset of my `pyproject.toml`:

```toml
[tool.mypy]
# SEE: http://mypy.readthedocs.io/en/latest/config_file.html#config-file

# Specifies the Python version used to parse and check the target program.
python_version = 3.10

# Enables PEP 420 style namespace packages.
namespace_packages = true
```

I invoke mypy via: `mypy -p namespacepkg`

**Expected Behavior**

<!--
  How did you expect your project to behave?
  It’s fine if you’re not sure your understanding is correct.
  Write down what you thought would happen. If you just expected no errors, you can delete this section.
-->

Not to raise this message.

**Actual Behavior**

<!--
  Did something go wrong?
  Is something broken, or not behaving as you expected?
-->

```
pyproject.toml: [mypy]: python_version: Python 3.1 is not supported (must be 3.4 or higher)
```

**Your Environment**

<!-- Include as many relevant details about the environment you experienced the bug in -->

- Mypy version used: 0.931
- Mypy command-line flags: n/a
- Mypy configuration options from `mypy.ini` (and other config files): see above `pyproject.toml`
- Python version used: 3.10.2
- Operating system and version: macOS v11.5.1 Big Sur

<!--
You can freely edit this text, please remove all the lines
you believe are unnecessary.
-->



Hints:
You need to quote it as `"3.10"`, because it's a float! We can probably put a special-case message here to make that clear though.
Changing it to:

```toml
# Specifies the Python version used to parse and check the target program.
python_version = "3.10"
```

Indeed fixes the problem. In hindsight it makes total sense.  Yeah maybe a special message would be a good idea, thank you!
@hauntsaninja Being a first-time contributor, I would like to work on this issue. Any suggestions on where I can start with?
@hauntsaninja @jamesbraza 
May I work on this issue?
@radioactive11 @nakatomotoi yes either of you can!  Just make a fork of mypy, cut a branch, try to implement a solution + add test(s) proving it works (see [`CONTRIBUTING.md`](https://github.com/python/mypy/blob/master/CONTRIBUTING.md) for how to run tests), and open a PR back to mypy's master branch.
@jamesbraza Sure!
@jamesbraza Should I add a special message when the version mentioned has two decimal digits or a general one?
There should be a message specific to this case (though it should also cover 3.11 and other future versions).

Patch:
diff --git a/mypy/config_parser.py b/mypy/config_parser.py
--- a/mypy/config_parser.py
+++ b/mypy/config_parser.py
@@ -24,8 +24,8 @@
 _INI_PARSER_CALLABLE: _TypeAlias = Callable[[Any], _CONFIG_VALUE_TYPES]
 
 
-def parse_version(v: str) -> Tuple[int, int]:
-    m = re.match(r'\A(\d)\.(\d+)\Z', v)
+def parse_version(v: Union[str, float]) -> Tuple[int, int]:
+    m = re.match(r'\A(\d)\.(\d+)\Z', str(v))
     if not m:
         raise argparse.ArgumentTypeError(
             f"Invalid python version '{v}' (expected format: 'x.y')")
@@ -36,9 +36,15 @@ def parse_version(v: str) -> Tuple[int, int]:
                 f"Python 2.{minor} is not supported (must be 2.7)")
     elif major == 3:
         if minor < defaults.PYTHON3_VERSION_MIN[1]:
-            raise argparse.ArgumentTypeError(
-                "Python 3.{} is not supported (must be {}.{} or higher)".format(minor,
-                                                                    *defaults.PYTHON3_VERSION_MIN))
+            msg = "Python 3.{0} is not supported (must be {1}.{2} or higher)".format(
+                minor,
+                *defaults.PYTHON3_VERSION_MIN
+            )
+
+            if isinstance(v, float):
+                msg += ". You may need to put quotes around your Python version"
+
+            raise argparse.ArgumentTypeError(msg)
     else:
         raise argparse.ArgumentTypeError(
             f"Python major version '{major}' out of range (must be 2 or 3)")
@@ -142,7 +148,7 @@ def check_follow_imports(choice: str) -> str:
 # Reuse the ini_config_types and overwrite the diff
 toml_config_types: Final[Dict[str, _INI_PARSER_CALLABLE]] = ini_config_types.copy()
 toml_config_types.update({
-    'python_version': lambda s: parse_version(str(s)),
+    'python_version': parse_version,
     'strict_optional_whitelist': try_split,
     'mypy_path': lambda s: [expand_path(p) for p in try_split(s, '[,:]')],
     'files': lambda s: split_and_match_files_list(try_split(s)),


Test patch:
diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test
--- a/test-data/unit/cmdline.test
+++ b/test-data/unit/cmdline.test
@@ -561,6 +561,15 @@ main.py:1: error: Cannot find implementation or library stub for module named "a
 main.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
 main.py:1: error: Cannot find implementation or library stub for module named "a"
 
+[case testPythonVersionWrongFormatPyProjectTOML]
+# cmd: mypy -c pass
+[file pyproject.toml]
+\[tool.mypy]
+python_version = 3.10
+[out]
+pyproject.toml: [mypy]: python_version: Python 3.1 is not supported (must be 3.4 or higher). You may need to put quotes around your Python version
+== Return code: 0
+
 [case testPythonVersionTooOld10]
 # cmd: mypy -c pass
 [file mypy.ini]