Repository: optuna/optuna-fast-fanova (language: python)

Issue:
Use `pyproject.toml` for setuptools and make Cython required.
## Motivation

Fixes #6.

As reported in #6, scikit-learn's C-API (Cython pxd file) is available to users, but many ABI changes have actually been made. optuna-fast-fanova contains a C extension file generated in Cython using scikit-learn v1.1.1, but scikit-learn v1.1.2 has the following changes to the ClassificationCriterion cdef class Therefore, it does not seem to be compatible with scikit-learn v1.1.2.
https://github.com/scikit-learn/scikit-learn/pull/22921

## Changes

Previously, the C extension file was included in the sdist package so that users without Cython could install optuna-fast-fanova. This approach is recommended at [Cython documentation](http://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html#distributing-cython-modules). However, as I described above, it is almost impossible to keep scikit-learn's ABI compatibility.
In this PR, I added a Cython dependency to setup_requires to generate a C extension file for each installation.

Furthermore, I move the project-metadata and build-system requirements to pyproject.toml since `setup_requires` is deprecated and `build-system.requires` is recommended option.
https://pip.pypa.io/en/stable/reference/build-system/index.html#controlling-setup-requires


Discussion / hints:
I confirmed that the sdist package can be installed as expected.

```
$ python3.9 -m venv venv
$ source venv/bin/activate
$ pip install git+https://github.com/optuna/optuna-fast-fanova.git@avoid-to-distribute-c-files
...
Successfully built optuna-fast-fanova
Installing collected packages: wcwidth, pyperclip, zipp, typing-extensions, tqdm, threadpoolctl, PyYAML, pyparsing, PrettyTable, pbr, numpy, MarkupSafe, joblib, greenlet, colorlog, autopage, attrs, stevedore, sqlalchemy, scipy, packaging, Mako, importlib-metadata, cmd2, cmaes, scikit-learn, cliff, alembic, optuna, optuna-fast-fanova
Successfully installed Mako-1.2.2 MarkupSafe-2.1.1 PrettyTable-3.4.1 PyYAML-6.0 alembic-1.8.1 attrs-22.1.0 autopage-0.5.1 cliff-4.0.0 cmaes-0.8.2 cmd2-2.4.2 colorlog-6.7.0 greenlet-1.1.3 importlib-metadata-4.12.0 joblib-1.1.0 numpy-1.23.3 optuna-3.0.1 optuna-fast-fanova-0.0.2 packaging-21.3 pbr-5.10.0 pyparsing-3.0.9 pyperclip-1.8.2 scikit-learn-1.1.2 scipy-1.8.1 sqlalchemy-1.4.41 stevedore-4.0.0 threadpoolctl-3.1.0 tqdm-4.64.1 typing-extensions-4.3.0 wcwidth-0.2.5 zipp-3.8.1
WARNING: You are using pip version 22.0.4; however, version 22.2.2 is available.
You should consider upgrading via the '/Users/c-bata/sandbox/optuna-fast-fanova-dist-check/venv/bin/python3.9 -m pip install --upgrade pip' command.
```

```python
import optuna
from optuna_fast_fanova import FanovaImportanceEvaluator


def objective(trial):
    x = trial.suggest_float("x", -10, 10)
    y = trial.suggest_int("y", -10, 10)
    return x ** 2 + y


if __name__ == "__main__":
    study = optuna.create_study()
    study.optimize(objective, n_trials=1000)

    importance = optuna.importance.get_param_importances(
        study, evaluator=FanovaImportanceEvaluator()
    )
    print(importance)
```

```
$ python example.py
...
OrderedDict([('x', 0.9865052228278766), ('y', 0.013494777172123431)])
```

Fix patch:
diff --git a/.github/workflows/build-python-dists.yml b/.github/workflows/build-python-dists.yml
index 46449b5..0ea681c 100644
--- a/.github/workflows/build-python-dists.yml
+++ b/.github/workflows/build-python-dists.yml
@@ -31,10 +31,10 @@ jobs:
       - name: Install dependencies
         run: |
           python3 -m pip install --progress-bar off --upgrade pip setuptools
+          python3 -m pip install numpy scikit-learn "Cython>=3.0.0a10"
 
       - name: Build sdist
-        run: |
-          python setup.py sdist
+        run: python3 setup.py sdist
 
       - name: Upload a sdist package to a GitHub release
         env:
diff --git a/setup.py b/setup.py
index 5ffe280..dc319f3 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 import os
 
-from Cython.Build import cythonize
+import Cython.Build
 import numpy
 from setuptools import Extension
 from setuptools import find_packages
@@ -9,17 +9,16 @@
 
 if __name__ == "__main__":
     setup(
-        packages=find_packages(exclude=("tests", "tests.*")),
-        ext_modules=cythonize(
-            [
-                Extension(
-                    "optuna_fast_fanova._fanova",
-                    sources=[os.path.join("optuna_fast_fanova", "_fanova.pyx")],
-                    include_dirs=[numpy.get_include()],
-                    language="c",
-                )
-            ]
-        ),
+        packages=find_packages(exclude=("tests", "tests.*", "example*")),
+        ext_modules=[
+            Extension(
+                "optuna_fast_fanova._fanova",
+                sources=[os.path.join("optuna_fast_fanova", "_fanova.pyx")],
+                include_dirs=[numpy.get_include()],
+                language="c",
+            )
+        ],
+        cmdclass={"build_ext": Cython.Build.build_ext},
         include_package_data=False,
         package_data={"optuna_fast_fanova": ["*.pyx"]},
     )
diff --git a/tools/example.py b/tools/example.py
new file mode 100644
index 0000000..437077e
--- /dev/null
+++ b/tools/example.py
@@ -0,0 +1,19 @@
+import optuna
+
+from optuna_fast_fanova import FanovaImportanceEvaluator
+
+
+def objective(trial):
+    x = trial.suggest_float("x", -10, 10)
+    y = trial.suggest_int("y", -10, 10)
+    return x**2 + y
+
+
+if __name__ == "__main__":
+    study = optuna.create_study()
+    study.optimize(objective, n_trials=1000)
+
+    importance = optuna.importance.get_param_importances(
+        study, evaluator=FanovaImportanceEvaluator()
+    )
+    print(importance)


Test patch:
diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml
index 3b4e9e0..52bd589 100644
--- a/.github/workflows/python-tests.yml
+++ b/.github/workflows/python-tests.yml
@@ -42,6 +42,24 @@ jobs:
           python3 setup.py build_ext --inplace
           pip install .
       - run: pytest tests
+  check-sdist:
+    strategy:
+      matrix:
+        os: [ubuntu-latest, macos-latest]
+    name: Check sdist package on ${{ matrix.os }}
+    runs-on: ${{ matrix.os }}
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.9
+          architecture: x64
+      - run: python3 -m pip install --progress-bar off --upgrade pip setuptools
+      - run: python3 -m pip install numpy scikit-learn "Cython>=3.0.0a10"
+      - run: python3 setup.py sdist
+      - run: python3 -m pip install ./dist/optuna-fast-fanova-*.*.*.tar.gz
+      - run: cd tools && python3 example.py  # Avoid relative import
   test-with-optuna-master:
     runs-on: ubuntu-latest
     steps: