Repository: numpy/numpy
Pull request: ENH: Warn on unsupported Python 3.10+
<!-- Please be sure you are following the instructions in the dev guidelines
http://www.numpy.org/devdocs/dev/development_workflow.html
-->

<!-- We'd appreciate it if your commit message is properly formatted
http://www.numpy.org/devdocs/dev/development_workflow.html#writing-the-commit-message
-->

<!-- If you're submitting a new feature or substantial change in functionality,
make sure you discuss your changes in the numpy-discussion mailing list first: 
https://mail.python.org/mailman/listinfo/numpy-discussion -->

<!-- We try to review your pull request as soon as we can, typically within a week.
If you do not get any review comments within two weeks, please feel free to ask for
feedback by adding a new comment on your PR (this will notify maintainers). If your
PR is large or complicated, asking for input on the numpy-discussion mailing
list may also be useful.
-->

Fixes https://github.com/numpy/numpy/issues/17349.

First commit (https://github.com/numpy/numpy/pull/17443/commits/f3a6b33144e62ce77aa767b73d930dec420a3511): warn when installing on unsupported (new) Python versions.

Based on the similar warning we have in Pillow:

* https://github.com/python-pillow/Pillow/blob/66209168847ad1b55190a629b49cc6ba829efe92/setup.py#L40-L47

(Not sure if this is an ENT or MAINT.)

---

Second commit (https://github.com/numpy/numpy/pull/17443/commits/2ebb45374d845ad6d4843e977c0ca03e53674d25): whilst editing `setup.py`, I also fixed some Flake8 warnings in there. Let me know if I should drop this commit, or parts of it.

Problem statement:
update PyPI classifiers to not install with unsupported Python versions
Right now if you do `pip-3.9 install numpy`, it will try to build NumPy for a version that does not support Python 3.9 yet (as stated in the release notes, and in `numpy/__init__.py`). We should see if we can fix the PyPI classifiers for this.

EDIT: or it's `python_requires='>=3.6'` in `setup.py`.

Hints from issue discussion:
It's definitely python_requires that's relevant.
Do you mean by setting an upper bound, like `python_requires='>=3.6,<3.9'`?

I think the new problem would be that pip will just loop through releases and reject any with that, but find an older version with `python_requires='>=3.6'` and fail on that instead. 

Yeah, I think @hugovk's point is a good one here - it sounds like doing this will make things worse not better.

Perhaps we should simply emit a warning in setup.py?
Good point. Warning in `setup.py` makes sense to me.

Commit message: MAINT: Fix Flake8

Patch to review:
diff --git a/setup.py b/setup.py
index 1f5212676310..a4e498af09a3 100755
--- a/setup.py
+++ b/setup.py
@@ -23,7 +23,7 @@
 import sys
 import subprocess
 import textwrap
-import sysconfig
+import warnings
 
 
 if sys.version_info[:2] < (3, 6):
@@ -59,6 +59,13 @@
 ISRELEASED          = False
 VERSION             = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
 
+if sys.version_info >= (3, 9):
+    warnings.warn(
+        f"NumPy {VERSION} does not support Python "
+        f"{sys.version_info.major}.{sys.version_info.minor}.",
+        RuntimeWarning,
+    )
+
 
 # Return the git revision as a string
 def git_version():
@@ -88,6 +95,7 @@ def _minimal_ext_cmd(cmd):
 
     return GIT_REVISION
 
+
 # BEFORE importing setuptools, remove MANIFEST. Otherwise it may not be
 # properly updated when the contents of directories change (true for distutils,
 # not sure about setuptools).
@@ -150,7 +158,7 @@ def write_version_py(filename='numpy/version.py'):
         a.close()
 
 
-def configuration(parent_package='',top_path=None):
+def configuration(parent_package='', top_path=None):
     from numpy.distutils.misc_util import Configuration
 
     config = Configuration(None, parent_package, top_path)
@@ -163,7 +171,7 @@ def configuration(parent_package='',top_path=None):
     config.add_data_files(('numpy', 'LICENSE.txt'))
     config.add_data_files(('numpy', 'numpy/*.pxd'))
 
-    config.get_version('numpy/version.py') # sets config.version
+    config.get_version('numpy/version.py')  # sets config.version
 
     return config
 
@@ -175,13 +183,12 @@ def check_submodules():
     if not os.path.exists('.git'):
         return
     with open('.gitmodules') as f:
-        for l in f:
-            if 'path' in l:
-                p = l.split('=')[-1].strip()
+        for line in f:
+            if 'path' in line:
+                p = line.split('=')[-1].strip()
                 if not os.path.exists(p):
                     raise ValueError('Submodule {} missing'.format(p))
 
-
     proc = subprocess.Popen(['git', 'submodule', 'status'],
                             stdout=subprocess.PIPE)
     status, _ = proc.communicate()
@@ -273,9 +280,9 @@ def generate_cython():
     print("Cythonizing sources")
     for d in ('random',):
         p = subprocess.call([sys.executable,
-                              os.path.join(cwd, 'tools', 'cythonize.py'),
-                              'numpy/{0}'.format(d)],
-                             cwd=cwd)
+                             os.path.join(cwd, 'tools', 'cythonize.py'),
+                             'numpy/{0}'.format(d)],
+                            cwd=cwd)
         if p != 0:
             raise RuntimeError("Running cythonize failed!")
 
@@ -346,7 +353,6 @@ def parse_setuppy_commands():
             """))
         return False
 
-
     # The following commands aren't supported.  They can only be executed when
     # the user explicitly adds a --force command-line argument.
     bad_commands = dict(
@@ -384,8 +390,8 @@ def parse_setuppy_commands():
         )
     bad_commands['nosetests'] = bad_commands['test']
     for command in ('upload_docs', 'easy_install', 'bdist', 'bdist_dumb',
-                     'register', 'check', 'install_data', 'install_headers',
-                     'install_lib', 'install_scripts', ):
+                    'register', 'check', 'install_data', 'install_headers',
+                    'install_lib', 'install_scripts', ):
         bad_commands[command] = "`setup.py %s` is not supported" % command
 
     for command in bad_commands.keys():
@@ -405,7 +411,8 @@ def parse_setuppy_commands():
     # If we got here, we didn't detect what setup.py command was given
     import warnings
     warnings.warn("Unrecognized setuptools command, proceeding with "
-                  "generating Cython sources and expanding templates", stacklevel=2)
+                  "generating Cython sources and expanding templates",
+                  stacklevel=2)
     return True
 
 
@@ -440,25 +447,24 @@ def setup_package():
             'f2py%s.%s = numpy.f2py.f2py2e:main' % sys.version_info[:2],
             ]
 
-    cmdclass={"sdist": sdist_checked,
-             }
+    cmdclass = {"sdist": sdist_checked, }
     metadata = dict(
-        name = 'numpy',
-        maintainer = "NumPy Developers",
-        maintainer_email = "numpy-discussion@python.org",
-        description = DOCLINES[0],
-        long_description = "\n".join(DOCLINES[2:]),
-        url = "https://www.numpy.org",
-        author = "Travis E. Oliphant et al.",
-        download_url = "https://pypi.python.org/pypi/numpy",
+        name='numpy',
+        maintainer="NumPy Developers",
+        maintainer_email="numpy-discussion@python.org",
+        description=DOCLINES[0],
+        long_description="\n".join(DOCLINES[2:]),
+        url="https://www.numpy.org",
+        author="Travis E. Oliphant et al.",
+        download_url="https://pypi.python.org/pypi/numpy",
         project_urls={
             "Bug Tracker": "https://github.com/numpy/numpy/issues",
             "Documentation": get_docs_url(),
             "Source Code": "https://github.com/numpy/numpy",
         },
-        license = 'BSD',
+        license='BSD',
         classifiers=[_f for _f in CLASSIFIERS.split('\n') if _f],
-        platforms = ["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"],
+        platforms=["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"],
         test_suite='pytest',
         cmdclass=cmdclass,
         python_requires='>=3.6',
@@ -479,8 +485,7 @@ def setup_package():
         # patches distutils, even though we don't use it
         import setuptools  # noqa: F401
         from numpy.distutils.core import setup
-        cwd = os.path.abspath(os.path.dirname(__file__))
-        if not 'sdist' in sys.argv:
+        if 'sdist' not in sys.argv:
             # Generate Cython sources, unless we're generating an sdist
             generate_cython()
 


Code review comments:
diff_hunk: @@ -59,6 +59,13 @@
 ISRELEASED          = False
 VERSION             = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
 
+if sys.version_info >= (3, 9):
+    warnings.warn(
+        f"NumPy {VERSION} does not support Python "
path: setup.py
text: @user1:
```suggestion
        f"NumPy {VERSION} does yet not support Python "
```
or perhaps
```suggestion
        f"NumPy {VERSION} may not yet support Python "
```

diff_hunk: @@ -59,6 +59,13 @@
 ISRELEASED          = False
 VERSION             = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
 
+if sys.version_info >= (3, 9):
path: setup.py
text: @user1:
```suggestion
# keep this consistent with the `Programming Language :: Python :: ...` classifiers above
if sys.version_info >= (3, 9):
```