|
1 | 1 | #!/usr/bin/env python
|
2 | 2 |
|
| 3 | +import argparse |
| 4 | + |
3 | 5 | import pandas as pd
|
4 | 6 | from packaging.specifiers import SpecifierSet
|
5 | 7 | from packaging.version import Version
|
6 | 8 |
|
7 | 9 |
|
8 |
| -def check_compatibility(row, min_python, min_numpy): |
| 10 | +def get_min_python_version(): |
| 11 | + """ |
| 12 | + Find the minimum version of Python supported (i.e., not end-of-life) |
| 13 | + """ |
| 14 | + min_python = ( |
| 15 | + pd.read_html("https://devguide.python.org/versions/")[0].iloc[-1].Branch |
| 16 | + ) |
| 17 | + return min_python |
| 18 | + |
| 19 | + |
| 20 | +def get_min_numba_numpy_version(min_python): |
| 21 | + """ |
| 22 | + Find the minimum versions of Numba and NumPy that supports the specified |
| 23 | + `min_python` version |
| 24 | + """ |
| 25 | + df = ( |
| 26 | + pd.read_html( |
| 27 | + "https://numba.readthedocs.io/en/stable/user/installing.html#version-support-information" # noqa |
| 28 | + )[0] |
| 29 | + .dropna() |
| 30 | + .drop(columns=["Numba.1", "llvmlite", "LLVM", "TBB"]) |
| 31 | + .query('`Python`.str.contains("2.7") == False') |
| 32 | + .query('`Numba`.str.contains(".x") == False') |
| 33 | + .query('`Numba`.str.contains("{") == False') |
| 34 | + .pipe( |
| 35 | + lambda df: df.assign( |
| 36 | + MIN_PYTHON_SPEC=( |
| 37 | + df.Python.str.split().str[1].replace({"<": ">"}, regex=True) |
| 38 | + + df.Python.str.split().str[0].replace({".x": ""}, regex=True) |
| 39 | + ).apply(SpecifierSet) |
| 40 | + ) |
| 41 | + ) |
| 42 | + .pipe( |
| 43 | + lambda df: df.assign( |
| 44 | + MAX_PYTHON_SPEC=( |
| 45 | + df.Python.str.split().str[3].replace({">": "<"}, regex=True) |
| 46 | + + df.Python.str.split().str[4].replace({".x": ""}, regex=True) |
| 47 | + ).apply(SpecifierSet) |
| 48 | + ) |
| 49 | + ) |
| 50 | + .pipe( |
| 51 | + lambda df: df.assign( |
| 52 | + MIN_NUMPY=(df.NumPy.str.split().str[0].replace({".x": ""}, regex=True)) |
| 53 | + ) |
| 54 | + ) |
| 55 | + .assign( |
| 56 | + COMPATIBLE=lambda row: row.apply( |
| 57 | + check_python_compatibility, axis=1, args=(Version(min_python),) |
| 58 | + ) |
| 59 | + ) |
| 60 | + .query("COMPATIBLE == True") |
| 61 | + .pipe(lambda df: df.assign(MINOR=df.Numba.str.split(".").str[1])) |
| 62 | + .pipe(lambda df: df.assign(PATCH=df.Numba.str.split(".").str[2])) |
| 63 | + .sort_values(["MINOR", "PATCH"], ascending=[False, True]) |
| 64 | + .iloc[-1] |
| 65 | + ) |
| 66 | + return df.Numba, df.MIN_NUMPY |
| 67 | + |
| 68 | + |
| 69 | +def check_python_compatibility(row, min_python): |
9 | 70 | """
|
10 |
| - Determines the Python and NumPy version compatibility |
| 71 | + Determine the Python version compatibility |
11 | 72 | """
|
12 | 73 | python_compatible = min_python in (row.MIN_PYTHON_SPEC & row.MAX_PYTHON_SPEC)
|
13 |
| - numpy_compatible = min_numpy in (row.MIN_NUMPY_SPEC & row.MAX_NUMPY_SPEC) |
14 |
| - return python_compatible & numpy_compatible |
| 74 | + return python_compatible |
15 | 75 |
|
16 | 76 |
|
17 |
| -MIN_PYTHON = "3.8" # Change this |
| 77 | +def check_scipy_compatibility(row, min_python, min_numpy): |
| 78 | + """ |
| 79 | + Determine the Python and NumPy version compatibility |
| 80 | + """ |
| 81 | + python_compatible = min_python in (row.MIN_PYTHON_SPEC & row.MAX_PYTHON_SPEC) |
| 82 | + numpy_compatible = min_numpy in (row.MIN_NUMPY_SPEC & row.MAX_NUMPY_SPEC) |
| 83 | + return python_compatible & numpy_compatible |
18 | 84 |
|
19 |
| -df = ( |
20 |
| - pd.read_html( |
21 |
| - "https://numba.readthedocs.io/en/stable/user/installing.html#version-support-information" # noqa |
22 |
| - )[0] |
23 |
| - .dropna() |
24 |
| - .query(f'Python.str.startswith("{MIN_PYTHON}")', engine="python") |
25 |
| - .pipe(lambda df: df.assign(NumPy=df.NumPy.str.split().str[0])) |
26 |
| - .iloc[-1] |
27 |
| -) |
28 |
| -MIN_NUMBA = df.Numba |
29 |
| -MIN_NUMPY = df.NumPy |
30 | 85 |
|
31 |
| -df = ( |
32 |
| - pd.read_html("https://docs.scipy.org/doc/scipy/dev/toolchain.html#numpy")[1] |
33 |
| - .replace({".x": ""}, regex=True) |
34 |
| - .rename(columns=lambda x: x.replace(" ", "_")) |
35 |
| - .query('`Python_versions`.str.contains("2.7") == False') |
36 |
| - .pipe( |
37 |
| - lambda df: df.assign( |
38 |
| - MIN_PYTHON_SPEC=df.Python_versions.str.split(",").str[0].apply(SpecifierSet) |
| 86 | +def get_min_scipy_version(min_python, min_numpy): |
| 87 | + """ |
| 88 | + Determine the SciPy version compatibility |
| 89 | + """ |
| 90 | + df = ( |
| 91 | + pd.read_html("https://docs.scipy.org/doc/scipy/dev/toolchain.html#numpy")[1] |
| 92 | + .rename(columns=lambda x: x.replace(" ", "_")) |
| 93 | + .replace({".x": ""}, regex=True) |
| 94 | + .pipe( |
| 95 | + lambda df: df.assign( |
| 96 | + SciPy_version=df.SciPy_version.str.replace( |
| 97 | + "\d\/", "", regex=True # noqa |
| 98 | + ) |
| 99 | + ) |
39 | 100 | )
|
40 |
| - ) |
41 |
| - .pipe( |
42 |
| - lambda df: df.assign( |
43 |
| - MAX_PYTHON_SPEC=df.Python_versions.str.split(",").str[1].apply(SpecifierSet) |
| 101 | + .query('`Python_versions`.str.contains("2.7") == False') |
| 102 | + .pipe( |
| 103 | + lambda df: df.assign( |
| 104 | + MIN_PYTHON_SPEC=df.Python_versions.str.split(",") |
| 105 | + .str[0] |
| 106 | + .apply(SpecifierSet) |
| 107 | + ) |
44 | 108 | )
|
45 |
| - ) |
46 |
| - .pipe( |
47 |
| - lambda df: df.assign( |
48 |
| - MIN_NUMPY_SPEC=df.NumPy_versions.str.split(",").str[0].apply(SpecifierSet) |
| 109 | + .pipe( |
| 110 | + lambda df: df.assign( |
| 111 | + MAX_PYTHON_SPEC=df.Python_versions.str.split(",") |
| 112 | + .str[1] |
| 113 | + .apply(SpecifierSet) |
| 114 | + ) |
49 | 115 | )
|
50 |
| - ) |
51 |
| - .pipe( |
52 |
| - lambda df: df.assign( |
53 |
| - MAX_NUMPY_SPEC=df.NumPy_versions.str.split(",").str[1].apply(SpecifierSet) |
| 116 | + .pipe( |
| 117 | + lambda df: df.assign( |
| 118 | + MIN_NUMPY_SPEC=df.NumPy_versions.str.split(",") |
| 119 | + .str[0] |
| 120 | + .apply(SpecifierSet) |
| 121 | + ) |
54 | 122 | )
|
55 |
| - ) |
56 |
| - .assign( |
57 |
| - COMPATIBLE=lambda row: row.apply( |
58 |
| - check_compatibility, axis=1, args=(Version(MIN_PYTHON), Version(MIN_NUMPY)) |
| 123 | + .pipe( |
| 124 | + lambda df: df.assign( |
| 125 | + MAX_NUMPY_SPEC=df.NumPy_versions.str.split(",") |
| 126 | + .str[1] |
| 127 | + .apply(SpecifierSet) |
| 128 | + ) |
59 | 129 | )
|
| 130 | + .assign( |
| 131 | + COMPATIBLE=lambda row: row.apply( |
| 132 | + check_scipy_compatibility, |
| 133 | + axis=1, |
| 134 | + args=(Version(min_python), Version(min_numpy)), |
| 135 | + ) |
| 136 | + ) |
| 137 | + .query("COMPATIBLE == True") |
| 138 | + .pipe(lambda df: df.assign(MINOR=df.SciPy_version.str.split(".").str[1])) |
| 139 | + .pipe(lambda df: df.assign(PATCH=df.SciPy_version.str.split(".").str[2])) |
| 140 | + .sort_values(["MINOR", "PATCH"], ascending=[False, True]) |
| 141 | + .iloc[-1] |
60 | 142 | )
|
61 |
| - .query("COMPATIBLE == True") |
62 |
| - .iloc[-1] |
63 |
| -) |
64 |
| -MIN_SCIPY = df.SciPy_version |
| 143 | + return df.SciPy_version |
| 144 | + |
65 | 145 |
|
66 |
| -print( |
67 |
| - f"python: {MIN_PYTHON}\nnumba: {MIN_NUMBA}\nnumpy: {MIN_NUMPY}\nscipy: {MIN_SCIPY}" |
68 |
| -) |
| 146 | +if __name__ == "__main__": |
| 147 | + parser = argparse.ArgumentParser() |
| 148 | + parser.add_argument("min_python", nargs="?", default=None) |
| 149 | + args = parser.parse_args() |
| 150 | + |
| 151 | + if args.min_python is not None: |
| 152 | + MIN_PYTHON = str(args.min_python) |
| 153 | + else: |
| 154 | + MIN_PYTHON = get_min_python_version() |
| 155 | + MIN_NUMBA, MIN_NUMPY = get_min_numba_numpy_version(MIN_PYTHON) |
| 156 | + MIN_SCIPY = get_min_scipy_version(MIN_PYTHON, MIN_NUMPY) |
| 157 | + print( |
| 158 | + f"python: {MIN_PYTHON}\n" |
| 159 | + f"numba: {MIN_NUMBA}\n" |
| 160 | + f"numpy: {MIN_NUMPY}\n" |
| 161 | + f"scipy: {MIN_SCIPY}" |
| 162 | + ) |
0 commit comments