Repository: python/mypy

Issue:
Drop all Python 3.2 support
We already don't support running mypy itself on Python 3.2. We've now decided that even supporting 3.2 as a target platform is too much work to maintain, so we're going to drop it completely.

See also https://github.com/python/typeshed/issues/1145.


Discussion:
The latest release of typing already dropped 3.2 support. Good to see this happening here as well! :)

Resolving patch:
diff --git a/mypy/main.py b/mypy/main.py
--- a/mypy/main.py
+++ b/mypy/main.py
@@ -121,11 +121,22 @@ def __getattr__(self, name: str) -> Any:
 
 def parse_version(v: str) -> Tuple[int, int]:
     m = re.match(r'\A(\d)\.(\d+)\Z', v)
-    if m:
-        return int(m.group(1)), int(m.group(2))
-    else:
+    if not m:
         raise argparse.ArgumentTypeError(
             "Invalid python version '{}' (expected format: 'x.y')".format(v))
+    major, minor = int(m.group(1)), int(m.group(2))
+    if major == 2:
+        if minor != 7:
+            raise argparse.ArgumentTypeError(
+                "Python 2.{} is not supported (must be 2.7)".format(minor))
+    elif major == 3:
+        if minor <= 2:
+            raise argparse.ArgumentTypeError(
+                "Python 3.{} is not supported (must be 3.3 or higher)".format(minor))
+    else:
+        raise argparse.ArgumentTypeError(
+            "Python major version '{}' out of range (must be 2 or 3)".format(major))
+    return major, minor
 
 
 # Make the help output a little less jarring.
@@ -553,8 +564,7 @@ def get_init_file(dir: str) -> Optional[str]:
 # exists to specify types for values initialized to None or container
 # types.
 config_types = {
-    # TODO: Check validity of python version
-    'python_version': lambda s: tuple(map(int, s.split('.'))),
+    'python_version': parse_version,
     'strict_optional_whitelist': lambda s: s.split(),
     'custom_typing_module': str,
     'custom_typeshed_dir': str,
@@ -663,7 +673,11 @@ def parse_section(prefix: str, template: Options,
             if ct is bool:
                 v = section.getboolean(key)  # type: ignore  # Until better stub
             elif callable(ct):
-                v = ct(section.get(key))
+                try:
+                    v = ct(section.get(key))
+                except argparse.ArgumentTypeError as err:
+                    print("%s: %s: %s" % (prefix, key, err), file=sys.stderr)
+                    continue
             else:
                 print("%s: Don't know what type %s should have" % (prefix, key), file=sys.stderr)
                 continue


Test patch:
diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py
--- a/mypy/test/testcheck.py
+++ b/mypy/test/testcheck.py
@@ -10,7 +10,7 @@
 from typing import Dict, List, Optional, Set, Tuple
 
 from mypy import build, defaults
-from mypy.main import parse_version, process_options
+from mypy.main import process_options
 from mypy.build import BuildSource, find_module_clear_caches
 from mypy.myunit import AssertionFailure
 from mypy.test.config import test_temp_dir, test_data_prefix
diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test
--- a/test-data/unit/check-unreachable-code.test
+++ b/test-data/unit/check-unreachable-code.test
@@ -404,9 +404,9 @@ x = 1
 [out]
 
 [case testCustomSysVersionInfo]
-# flags: --python-version 3.2
+# flags: --python-version 3.5
 import sys
-if sys.version_info == (3, 2):
+if sys.version_info == (3, 5):
     x = "foo"
 else:
     x = 3
@@ -415,9 +415,9 @@ reveal_type(x)  # E: Revealed type is 'builtins.str'
 [out]
 
 [case testCustomSysVersionInfo2]
-# flags: --python-version 3.1
+# flags: --python-version 3.5
 import sys
-if sys.version_info == (3, 2):
+if sys.version_info == (3, 6):
     x = "foo"
 else:
     x = 3
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
@@ -514,3 +514,64 @@ whatever
 main.py:1: error: Cannot find module named 'a'
 main.py:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
 main.py:1: error: Cannot find module named 'a.b'
+
+[case testPythonVersionTooOld10]
+# cmd: mypy -c pass
+[file mypy.ini]
+[[mypy]
+python_version = 1.0
+[out]
+mypy.ini: [mypy]: python_version: Python major version '1' out of range (must be 2 or 3)
+
+[case testPythonVersionTooOld26]
+# cmd: mypy -c pass
+[file mypy.ini]
+[[mypy]
+python_version = 2.6
+[out]
+mypy.ini: [mypy]: python_version: Python 2.6 is not supported (must be 2.7)
+
+[case testPythonVersionTooOld32]
+# cmd: mypy -c pass
+[file mypy.ini]
+[[mypy]
+python_version = 3.2
+[out]
+mypy.ini: [mypy]: python_version: Python 3.2 is not supported (must be 3.3 or higher)
+
+[case testPythonVersionTooNew28]
+# cmd: mypy -c pass
+[file mypy.ini]
+[[mypy]
+python_version = 2.8
+[out]
+mypy.ini: [mypy]: python_version: Python 2.8 is not supported (must be 2.7)
+
+[case testPythonVersionTooNew40]
+# cmd: mypy -c pass
+[file mypy.ini]
+[[mypy]
+python_version = 4.0
+[out]
+mypy.ini: [mypy]: python_version: Python major version '4' out of range (must be 2 or 3)
+
+[case testPythonVersionAccepted27]
+# cmd: mypy -c pass
+[file mypy.ini]
+[[mypy]
+python_version = 2.7
+[out]
+
+[case testPythonVersionAccepted33]
+# cmd: mypy -c pass
+[file mypy.ini]
+[[mypy]
+python_version = 3.3
+[out]
+
+[case testPythonVersionAccepted36]
+# cmd: mypy -c pass
+[file mypy.ini]
+[[mypy]
+python_version = 3.6
+[out]