Skip to content

remove License from classifiers #141

remove License from classifiers

remove License from classifiers #141

Workflow file for this run

# Gradient-Free-Optimizers CI Pipeline
#
# Pipeline Structure:
# 1. Code Quality (gate) - Must pass before anything else runs
# 2. API Smoke Tests (gate) - Fast API freeze tests, must pass before main tests
# 3. Main Tests (parallel):
# - OS Matrix Tests (Ubuntu, macOS, Windows × Python versions)
# - Dependency Isolation Tests (no-sklearn, no-scipy)
# 4. Coverage - Runs after all tests pass
name: CI
on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ===========================================================================
# STAGE 1: Code Quality (gate)
# ===========================================================================
code-quality:
name: Code Quality
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install pre-commit
run: python -m pip install --no-cache-dir pre-commit
- name: Get changed files
id: changed-files
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | tr '\n' ' ')
else
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD | tr '\n' ' ')
fi
echo "CHANGED_FILES=${CHANGED_FILES}" >> $GITHUB_ENV
- name: Print changed files
run: |
echo "Changed files:" && echo "$CHANGED_FILES" | tr ' ' '\n'
- name: Run pre-commit on changed files
run: |
if [ -n "$CHANGED_FILES" ]; then
pre-commit run --color always --files $CHANGED_FILES --show-diff-on-failure
else
echo "No changed files to check."
fi
# ===========================================================================
# STAGE 2: API Smoke Tests (gate)
# ===========================================================================
api-smoke-tests:
name: API Smoke Tests
runs-on: ubuntu-latest
needs: code-quality
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install build
make install
make install-test-requirements
- name: Reinstall in editable mode for coverage
run: pip install -e .
- name: Run API smoke tests
run: >-
python -m pytest tests/test_api/ -v --tb=short -p no:warnings
--cov=gradient_free_optimizers --cov-report=
- name: Rename coverage data
run: mv .coverage .coverage.api-smoke
- name: Upload coverage data
uses: actions/upload-artifact@v4
with:
name: coverage-api-smoke
path: .coverage.api-smoke
include-hidden-files: true
# ===========================================================================
# STAGE 3a: Main Tests - OS Matrix
# ===========================================================================
test-matrix:
name: Tests (${{ matrix.os }}, py${{ matrix.python-version }}, np${{ matrix.numpy-version }})
runs-on: ${{ matrix.os }}
needs: api-smoke-tests
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
numpy-version: ["1", "2"]
exclude:
# numpy 1.x not compatible with Python 3.13+
- python-version: "3.13"
numpy-version: "1"
- python-version: "3.14"
numpy-version: "1"
# pandas 1.x has no pre-built wheel for Python 3.12, source build
# broken since setuptools 81 removed pkg_resources (Feb 2026)
- python-version: "3.12"
numpy-version: "1"
# Reduce macOS/Windows matrix to save CI minutes
- os: macos-latest
numpy-version: "1"
- os: windows-latest
numpy-version: "1"
fail-fast: false
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install build
make install
make install-test-requirements
- name: Install specific numpy/pandas versions
shell: bash
run: |
if [ "${{ matrix.numpy-version }}" = "1" ]; then
python -m pip install "numpy>=1.18.1,<2.0.0" "pandas>=1.0,<2.0"
else
python -m pip install "numpy>=2.0,<3.0" "pandas>=2.0,<3.0"
fi
- name: Reinstall in editable mode for coverage
if: matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest' && matrix.numpy-version == '2'
run: pip install -e .
- name: Run main tests
run: >-
python -m pytest tests/test_main/ -v --tb=short -p no:warnings
${{ matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest' && matrix.numpy-version == '2' && '--cov=gradient_free_optimizers --cov-report=' || '' }}
- name: Rename coverage data
if: matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest' && matrix.numpy-version == '2'
run: mv .coverage .coverage.test-matrix
- name: Upload coverage data
if: matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest' && matrix.numpy-version == '2'
uses: actions/upload-artifact@v4
with:
name: coverage-test-matrix
path: .coverage.test-matrix
include-hidden-files: true
# ===========================================================================
# STAGE 3b: Dependency Isolation Tests - No sklearn
# ===========================================================================
# TEMPORARILY DISABLED - Re-enable when dependency isolation testing is needed
# test-no-sklearn:
# name: Tests (no sklearn)
# runs-on: ubuntu-latest
# needs: api-smoke-tests
# steps:
# - name: Checkout code
# uses: actions/checkout@v4
# - name: Set up Python 3.11
# uses: actions/setup-python@v5
# with:
# python-version: "3.11"
# - name: Install minimal dependencies (no sklearn)
# run: |
# python -m pip install --upgrade pip
# python -m pip install build numpy pandas pytest
# python -m pip install scipy
# - name: Build and install package
# run: |
# python -m pip install build
# python -m build
# pip install dist/*.whl
# - name: Verify sklearn is NOT installed
# run: |
# python -c "
# import sys
# try:
# import sklearn
# print('ERROR: sklearn is installed but should not be!')
# sys.exit(1)
# except ImportError:
# print('OK: sklearn is not installed')
# "
# - name: Run dependency isolation tests
# run: |
# python -m pytest tests/test_dependencies/test_no_sklearn.py -v --tb=short -p no:warnings
# ===========================================================================
# STAGE 3b: Dependency Isolation Tests - No scipy
# ===========================================================================
test-no-scipy:
name: Tests (no scipy)
runs-on: ubuntu-latest
needs: api-smoke-tests
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install minimal dependencies (no scipy)
run: |
python -m pip install --upgrade pip
python -m pip install build numpy pandas pytest tqdm
- name: Build and install package
run: |
python -m pip install build
python -m build
pip install dist/*.whl
- name: Verify scipy is NOT installed
run: |
python -c "
import sys
try:
import scipy
print('ERROR: scipy is installed but should not be!')
sys.exit(1)
except ImportError:
print('OK: scipy is not installed')
"
- name: Run dependency isolation tests
run: |
python -m pytest tests/test_dependencies/test_no_scipy.py -v --tb=short -p no:warnings
# ===========================================================================
# STAGE 3c: Pure Python Backend (no numpy, no scipy, no C extension)
# ===========================================================================
test-pure-python:
name: Backend (pure Python)
runs-on: ubuntu-latest
needs: api-smoke-tests
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Build and install WITHOUT C extension
env:
GFO_DISABLE_C_EXTENSION: "1"
run: |
python -m pip install --upgrade pip
python -m pip install build pytest tqdm setuptools
python -m build
pip install dist/*.whl
pip uninstall numpy pandas scipy -y 2>/dev/null || true
- name: Verify pure Python environment
run: |
python -c "
import sys
errors = []
for mod in ('numpy', 'scipy'):
try:
__import__(mod)
errors.append(f'{mod} is importable but should not be')
except ImportError:
print(f'OK: {mod} not installed')
from gradient_free_optimizers._array_backend import (
HAS_NUMPY, HAS_C_EXTENSION, _backend_name, array,
)
from gradient_free_optimizers._array_backend._pure import GFOArray
if HAS_NUMPY:
errors.append('HAS_NUMPY is True')
if HAS_C_EXTENSION:
errors.append('HAS_C_EXTENSION is True')
if _backend_name != 'pure':
errors.append(f'_backend_name is {_backend_name!r}, expected pure')
a = array([1.0, 2.0])
if type(a) is not GFOArray:
errors.append(f'array() returned {type(a).__name__}, expected GFOArray')
if errors:
for e in errors:
print(f'FAIL: {e}')
sys.exit(1)
print('OK: pure Python backend verified')
"
- name: Run backend tests (unit + integration + backend verification)
run: |
python -m pytest tests/test_dependencies/test_backend_pure.py -v --tb=short -p no:warnings
# ===========================================================================
# STAGE 3d: C Extension Backend (no numpy, no scipy, with compiled C)
# ===========================================================================
test-c-extension:
name: Backend (C extension)
runs-on: ubuntu-latest
needs: api-smoke-tests
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Build and install WITH C extension
run: |
python -m pip install --upgrade pip
python -m pip install build pytest tqdm setuptools
python -m build
pip install dist/*.whl
pip uninstall numpy pandas scipy -y 2>/dev/null || true
- name: Verify C extension environment
run: |
python -c "
import sys
errors = []
for mod in ('numpy', 'scipy'):
try:
__import__(mod)
errors.append(f'{mod} is importable but should not be')
except ImportError:
print(f'OK: {mod} not installed')
from gradient_free_optimizers._array_backend import (
HAS_NUMPY, HAS_C_EXTENSION, _backend_name, array,
)
from gradient_free_optimizers._array_backend._c_extension import _CGFOArray
if HAS_NUMPY:
errors.append('HAS_NUMPY is True')
if not HAS_C_EXTENSION:
errors.append('HAS_C_EXTENSION is False (C extension not compiled)')
if _backend_name != 'c_extension':
errors.append(f'_backend_name is {_backend_name!r}, expected c_extension')
a = array([1.0, 2.0])
if type(a) is not _CGFOArray:
errors.append(f'array() returned {type(a).__name__}, expected _CGFOArray')
if errors:
for e in errors:
print(f'FAIL: {e}')
sys.exit(1)
print('OK: C extension backend verified')
"
- name: Run C extension unit tests
run: |
python -m pytest tests/test_internal/test_array_backend/test_c_extension.py -v --tb=short -p no:warnings
- name: Run backend tests (unit + integration + backend verification)
run: |
python -m pytest tests/test_dependencies/test_backend_c_extension.py -v --tb=short -p no:warnings
# ===========================================================================
# STAGE 4: Coverage Report (only on Ubuntu with full dependencies)
# ===========================================================================
coverage:
name: Coverage Report
runs-on: ubuntu-latest
needs: [test-matrix, test-no-scipy, test-pure-python, test-c-extension]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install coverage
run: pip install "coverage[toml]"
- name: Download all coverage data
uses: actions/download-artifact@v4
with:
pattern: coverage-*
merge-multiple: true
- name: Combine coverage data
run: |
coverage combine
coverage report --show-missing
coverage xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
fail_ci_if_error: false
verbose: true