Repository: 392781/scikit-ntk (language: python)

Issue:
Create a CI/CD pipeline
Be able to automatically:
* Lint
* Test
* Build
* Publish (Github release + pypi)



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml
new file mode 100644
index 0000000..3b32b5d
--- /dev/null
+++ b/.github/workflows/CD.yml
@@ -0,0 +1,40 @@
+name: Publish to PyPI
+
+on:
+  release:
+    types: [published]
+
+permissions:
+  contents: read
+
+jobs:     
+  deploy:
+    strategy:
+      fail-fast: true
+      matrix:
+        python-version: ['3.x']
+        poetry-version: ['1.2.2']
+        os: [ubuntu-latest]
+
+    runs-on: ${{ matrix.os }}
+
+    steps:
+    - uses: actions/checkout@v3
+    
+    - name: Setting up latest Python version
+      uses: actions/setup-python@v4
+      with:
+        python-version: ${{ matrix.python-version }}
+        
+    - name: Running Poetry image
+      uses: abatilo/actions-poetry@v2
+      with:
+        poetry-version: ${{ matrix.poetry-version }}
+      
+    - name: Publishing test run
+      run: |
+        poetry publish --build --dry-run
+        
+    - name: Publishing scikit-ntk to PyPI
+      run: |
+        poetry publish --build --username __token__ --password ${{ secrets.PYPI_API_TOKEN }}
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
new file mode 100644
index 0000000..f7772ff
--- /dev/null
+++ b/.github/workflows/CI.yml
@@ -0,0 +1,69 @@
+name: Lint, Build, Install, Test
+
+on:
+  push:
+    branches:
+    - master
+  pull_request:
+    paths: 
+    - 'example/**'
+    - 'skntk/**'
+    - 'tests/**'
+  workflow_dispatch:
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v3
+
+    - name: Setting up latest stable Python version
+      uses: actions/setup-python@v4
+      with:
+        python-version: '3.x'
+    
+    - name: Installing dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install flake8
+    
+    - name: Analyzing files using flake8 with options
+      run: |
+        flake8 . --max-line-length=100 --show-source --statistics --ignore=F401,W503
+
+  ci:
+    strategy:
+      fail-fast: false
+      matrix:
+        python-version: ['3.7', '3.8', '3.9', '3.10']
+        poetry-version: ['1.2.2']
+        os: [ubuntu-latest, macos-latest, windows-latest]
+
+    runs-on: ${{ matrix.os }}
+
+    steps:
+      - uses: actions/checkout@v3
+
+      - name: Setting up Python version ${{ matrix.python-version }}
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ matrix.python-version }}
+
+      - name: Running Poetry image
+        uses: abatilo/actions-poetry@v2
+        with:
+          poetry-version: ${{ matrix.poetry-version }}
+
+      - name: Building scikit-ntk
+        run: |
+          poetry build
+      
+      - name: Installing dependencies
+        run: |
+          python -m pip install --upgrade pip
+          poetry install --with dev
+
+      - name: Testing scikit-ntk
+        run: |
+          poetry run pytest
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
deleted file mode 100644
index 55267c8..0000000
--- a/.github/workflows/lint.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: Python Linting
-
-on: [push, pull_request]
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        python-version: ["3.7", "3.8", "3.9", "3.10"]
-
-    steps:
-    - uses: actions/checkout@v3
-
-    - name: Setting up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v3
-      with:
-        python-version: ${{ matrix.python-version }}
-    
-    - name: Installing dependencies
-      run: |
-        python -m pip install --upgrade pip
-        pip install flake8
-    
-    - name: Analyzing files using flake8 with options
-      run: |
-        flake8 . --max-line-length=100 --ignore=F401,W503
\ No newline at end of file
diff --git a/README.md b/README.md
index 6c1067a..b0f2428 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,23 @@ kernel_ntk = NTK(D=3, bias=0.01, bias_bounds=(1e-6, 1e6))
 ```
 Once declared, usage is the same as other `scikit-learn` kernels.
 
+## Building
+Python Poetry (>=1.2) is required if you wish to build `scikit-ntk` from source.  In order to build follow these steps:
+
+1. Clone the repository
+```bash
+git clone git@github.com:392781/scikit-ntk.git
+```
+2. Enable a Poetry virtual environment
+```bash
+poetry shell
+```
+3. Build and install
+```bash
+poetry build
+poetry install --with dev
+```
+
 ## Citation
 
 If you use scikit-ntk in your scientific work, please use the following citation alongside the scikit-learn citations found at [https://scikit-learn.org/stable/about.html#citing-scikit-learn](https://scikit-learn.org/stable/about.html#citing-scikit-learn):
diff --git a/pyproject.toml b/pyproject.toml
index eb43bde..9525058 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,6 @@
 [tool.poetry]
-
 name = "scikit-ntk"
-version = "1.0.1"
+version = "1.1.0-dev"
 description = "Implementation of the neural tangent kernel for scikit-learn's Gaussian process module."
 license="BSD-3-Clause"
 authors = [
@@ -22,10 +21,18 @@ classifiers = [
 ]
 
 [tool.poetry.urls]
-
 "Bug Tracker" = "https://github.com/392781/scikit-ntk/issues"
 
 [tool.poetry.dependencies]
-
 python = "^3.7"
-scikit-learn = "^1.0.1"
+scikit-learn = [
+    {version = "^1.0.0", python = ">=3.7,<3.10"},
+    {version = "^1.1", python = ">=3.10"}
+]
+
+[tool.poetry.group.dev.dependencies]
+pytest = "^7.1.3"
+flake8 = "^5.0.4"
+
+[tool.pytest.ini_options]
+testpaths = ["tests"]


Test patch:
diff --git a/tests/test_gp.py b/tests/test_gp.py
new file mode 100644
index 0000000..5daad86
--- /dev/null
+++ b/tests/test_gp.py
@@ -0,0 +1,1 @@
+from skntk import NeuralTangentKernel as NTK
diff --git a/tests/test_kernel.py b/tests/test_kernel.py
new file mode 100644
index 0000000..2c59543
--- /dev/null
+++ b/tests/test_kernel.py
@@ -0,0 +1,28 @@
+import pytest
+import numpy as np
+
+from sklearn.gaussian_process.kernels import _approx_fprime
+from numpy.testing import assert_almost_equal
+from skntk import NeuralTangentKernel as NTK
+
+X = np.random.RandomState(0).normal(0, 1, (5, 2))
+Y = np.random.RandomState(0).normal(0, 1, (6, 2))
+
+ntk = NTK(depth=3, bias=0.01, bias_bounds=(1e-5, 1e3))
+
+
+def test_kernel_gradient():
+    # Compare analytic and numeric gradient of kernels.
+    K, K_gradient = ntk(X, eval_gradient=True)
+
+    assert K_gradient.shape[0] == X.shape[0]
+    assert K_gradient.shape[1] == X.shape[0]
+    assert K_gradient.shape[2] == ntk.theta.shape[0]
+
+    def eval_kernel_for_theta(theta):
+        ntk_clone = ntk.clone_with_theta(theta)
+        K = ntk_clone(X, eval_gradient=False)
+        return K
+
+    K_gradient_approx = _approx_fprime(ntk.theta, eval_kernel_for_theta, 1e-10)
+    assert_almost_equal(K_gradient, K_gradient_approx, 4)