Skip to content

Merge pull request #161 from Grid2op/claude/security-audit-review-jghnx0 #880

Merge pull request #161 from Grid2op/claude/security-audit-review-jghnx0

Merge pull request #161 from Grid2op/claude/security-audit-review-jghnx0 #880

Workflow file for this run

name: CI
on:
push:
branches:
- '*'
tags:
- 'v*.*.*'
env:
# ── Wheel count guard ─────────────────────────────────────────────────────
# Must be updated in sync with the build matrix whenever a Python version
# is added or removed. A mismatch blocks the lightsim2grid-wheels artifact
# from being created, which in turn prevents the PyPI release workflow
# (publish.yml) from running at all.
#
# manylinux x86_64 (cp39–cp314 × 1 container) → 6
# windows x64 (cp39–cp314 × AMD64) → 6
# macos x86_64 (cp39–cp314, native on macos-15-intel) → 6
# macos arm64 (cp310–cp314, native on macos-14) → 5
# exotic macos arm64 via cibuildwheel (cp39) → 1
# exotic windows ARM64 via cibuildwheel (cp39–cp314) → 6
# total: 30
EXPECTED_WHEELS: 30
EXPECTED_SDIST: 1
jobs:
manylinux_build:
# build wheels for some linux
name: Build linux ${{ matrix.python.name }} wheel on ${{ matrix.cont.name}}
runs-on: ${{matrix.cont.runner}}
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
strategy:
matrix:
python:
# - {
# name: cp37,
# abi: cp37m,
# version: '3.7',
# }
# - {
# name: cp38,
# abi: cp38,
# version: '3.8',
# }
- {
name: cp39,
abi: cp39,
version: '3.9',
}
- {
name: cp310,
abi: cp310,
version: '3.10',
}
- {
name: cp311,
abi: cp311,
version: '3.11',
}
- {
name: cp312,
abi: cp312,
version: '3.12',
}
- {
name: cp313,
abi: cp313,
version: '3.13',
}
- {
name: cp314,
abi: cp314,
version: '3.14',
}
cont:
- {
name: manylinux_2_28_x86_64,
val: quay.io/pypa/manylinux_2_28_x86_64,
arch: amd64,
runner: ubuntu-latest
}
# - {
# name: manylinux_2_28_aarch64,
# val: quay.io/pypa/manylinux_2_28_aarch64,
# arch: arm64,
# runner: ubuntu-24.04-arm
# }
container:
image: ${{matrix.cont.val}}
# does not work if not manylinux2014_x86_64...
# does not work if not manylinux_2_28_x86_64...
steps:
# - name: Set up QEMU
# if: matrix.cont.name == 'manylinux_2_28_aarch64'
# uses: docker/setup-qemu-action@v2
# with:
# platforms: arm64
- name: Checkout sources
uses: actions/checkout@v4
with:
submodules: true
- name: Setup path
run: echo "/opt/python/${{ matrix.python.name }}-${{ matrix.python.abi }}/bin/" >> $GITHUB_PATH
- name: get python version
run: |
python3 --version
- name: Install Python dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements_compile_ci.txt
python3 -m pip freeze
- name: Build lightsim2grid wheel
run: |
python3 -m pip wheel --verbose . --no-deps -w dist
auditwheel repair dist/*.whl
- name: Build source archive
if: matrix.python.name == 'cp312'
run: |
python3 -m pip install build
python3 -m build --sdist
- name: Install lightsim2grid wheel
run: |
python3 -m pip install wheelhouse/*.whl --user
python3 -m pip freeze
- name: Check package can be imported (bare install, default numpy)
run: |
mkdir tmp_for_import_checking
cd tmp_for_import_checking
python3 -c "import lightsim2grid"
python3 -c "from lightsim2grid import *"
python3 -c "from lightsim2grid.newtonpf import newtonpf"
python3 -c "from lightsim2grid.timeSerie import TimeSeriesCPP"
python3 -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP"
python3 -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP"
python3 -c "from lightsim2grid.network import LSGrid"
- name: Check package can be imported (bare install, numpy < 2)
if: matrix.python.name != 'cp37' && matrix.python.name != 'cp38' && matrix.python.name != 'cp313' && matrix.python.name != 'cp314'
run: |
python3 -m pip install "numpy<2" scipy
cd tmp_for_import_checking
python3 -c "import lightsim2grid"
python3 -c "from lightsim2grid import *"
python3 -c "from lightsim2grid.newtonpf import newtonpf"
python3 -c "from lightsim2grid.timeSerie import TimeSeriesCPP"
python3 -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP"
python3 -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP"
python3 -c "from lightsim2grid.network import LSGrid"
- name: Fix urllib3 (python 3.7)
if: matrix.python.name == 'cp37'
run:
pip install urllib3==1.26.6
# otherwise urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips 26 Jan 2017'
- name: Install grid2op
if: matrix.python.name != 'cp313' # pandapower does not support 3.13, so grid2op does not so I cannot test that for 3.13
run: |
python3 -m pip install grid2op pandapower lxml # lxml missing import see https://github.com/e2nIEE/pandapower/issues/2752
python3 -m pip freeze
- name: Check extra can be imported can be imported (with grid2op)
if: matrix.python.name != 'cp313' # pandapower does not support 3.13, so grid2op does not so I cannot test that for 3.13
run: |
cd tmp_for_import_checking
python3 -v -c "from lightsim2grid import LightSimBackend"
python3 -c "from lightsim2grid.timeSerie import TimeSerie"
python3 -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysis"
python3 -c "from lightsim2grid.physical_law_checker import PhysicalLawChecker"
python3 -c "from lightsim2grid.securityAnalysis import SecurityAnalysis"
python3 -c "from lightsim2grid.network import init_from_pandapower"
- name: Check LightSimBackend can be used to create env
if: matrix.python.name != 'cp313' # pandapower does not support 3.13, so grid2op does not so I cannot test that for 3.13
run: |
cd tmp_for_import_checking
python3 -v -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: lightsim2grid-wheel-linux-${{ matrix.python.name }}-${{ matrix.cont.name }}
path: wheelhouse/*.whl
- name: Upload source archive
uses: actions/upload-artifact@v4
if: matrix.python.name == 'cp312'
with:
name: lightsim2grid-sources
path: dist/*.tar.gz
windows_build:
# build wheels for windows
name: Build windows ${{ matrix.python.name }} wheel for ${{ matrix.win_arch.msvc}}
runs-on: windows-2022
strategy:
matrix:
python:
# - {
# name: cp37,
# version: '3.7',
# }
# - {
# name: cp38,
# version: '3.8',
# }
- {
name: cp39,
version: '3.9',
}
- {
name: cp310,
version: '3.10',
}
- {
name: cp311,
version: '3.11',
}
- {
name: cp312,
version: '3.12',
}
- {
name: cp313,
version: '3.13',
}
- {
name: cp314,
version: '3.14',
}
win_arch:
- {
name: "AMD64",
msvc: x64
}
# - {
# name: "x86",
# msvc: x86
# }
env:
RUNNER_OS: windows-2022
PYTHON_VERSION: ${{ matrix.python.version }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
with:
submodules: true
- name: Setup Python ${{ matrix.python.version }} ${{ matrix.win_arch.msvc}}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python.version }}
architecture: ${{ matrix.win_arch.msvc}}
- name: Setup MSVC ${{ matrix.win_arch.msvc}}
uses: bus1/cabuild/action/msdevshell@e22aba57d6e74891d059d66501b6b5aed8123c4d # v1
with:
architecture: ${{ matrix.win_arch.msvc}}
- name: Install Python dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements_compile_ci.txt
python3 -m pip freeze
- name: Build wheel
run: python -m pip wheel --verbose . --no-deps -w dist
- name: Install wheel
shell: bash
run: python -m pip install dist/*.whl --user
- name: Check package can be imported (bare install, default numpy)
run: |
mkdir tmp_for_import_checking
cd tmp_for_import_checking
python3 -c "import lightsim2grid"
python3 -c "from lightsim2grid import *"
python3 -c "from lightsim2grid.newtonpf import newtonpf"
python3 -c "from lightsim2grid.timeSerie import TimeSeriesCPP"
python3 -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP"
python3 -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP"
python3 -c "from lightsim2grid.network import LSGrid"
- name: Check package can be imported (bare install, numpy < 2)
if: matrix.python.name != 'cp37' && matrix.python.name != 'cp38' && matrix.python.name != 'cp313' && matrix.python.name != 'cp314'
run: |
python3 -m pip install "numpy<2" scipy
cd tmp_for_import_checking
python3 -c "import lightsim2grid"
python3 -c "from lightsim2grid import *"
python3 -c "from lightsim2grid.newtonpf import newtonpf"
python3 -c "from lightsim2grid.timeSerie import TimeSeriesCPP"
python3 -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP"
python3 -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP"
python3 -c "from lightsim2grid.network import LSGrid"
python3 -m pip install --upgrade numpy
- name: Check LightSimBackend can be imported (with grid2op)
if: matrix.python.name != 'cp314' # pandapower does not support 3.14, so grid2op does not so I cannot test that for 3.14
run: |
python -m pip install grid2op lxml # lxml missing import see https://github.com/e2nIEE/pandapower/issues/2752
cd tmp_for_import_checking
python -c "from lightsim2grid import LightSimBackend"
python -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
python -c "from lightsim2grid.timeSerie import TimeSerie"
python -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysis"
python -c "from lightsim2grid.physical_law_checker import PhysicalLawChecker"
python -c "from lightsim2grid.securityAnalysis import SecurityAnalysis"
python -c "from lightsim2grid.network import init_from_pandapower"
- name: Check LightSimBackend can be used to create env
if: matrix.python.name != 'cp314' # pandapower does not support 3.14, so grid2op does not so I cannot test that for 3.14
run: |
cd tmp_for_import_checking
python3 -v -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
# - name: Debug windows CI
# run: |
# python -m unittest lightsim2grid.tests.test_n1contingencyrewards.TestN1ContingencyReward_Base.test_do_nothing
- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: lightsim2grid-wheel-win-${{ matrix.python.name }}-${{ matrix.win_arch.msvc}}
path: dist/*.whl
macos_build_37_:
## build wheel for python 3.7 and above for macos (only >= 3.10 for arm64 )
name: Build darwin ${{ matrix.python.name }} wheel on ${{ matrix.runner.arch}}
runs-on: ${{ matrix.runner.name }}
strategy:
matrix:
python:
# - {
# name: cp37,
# version: '3.7',
# }
# - {
# name: cp38,
# version: '3.8',
# }
- {
name: cp39,
version: '3.9',
}
- {
name: cp310,
version: '3.10',
}
- {
name: cp311,
version: '3.11',
}
- {
name: cp312,
version: '3.12',
}
- {
name: cp313,
version: '3.13',
}
- {
name: cp314,
version: '3.14',
}
runner:
- {
name: macos-15-intel,
arch: x86_64
}
- {
name: macos-14,
arch: arm64
}
exclude:
- python: # does not work
name: cp37
runner:
arch: arm64
- python: # does not work
name: cp38
runner:
arch: arm64
- python: # does not work
name: cp39
runner:
arch: arm64
env:
RUNNER_OS: ${{ matrix.runner.name }}
PYTHON_VERSION: ${{ matrix.python.version }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
with:
submodules: true
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python.version }}
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements_compile_ci.txt
python -m pip freeze
- name: Build wheel
run: python -m pip wheel --verbose . --no-deps -w dist
- name: Install wheel
shell: bash
run: |
python -m pip install dist/*.whl --user
python -m pip freeze
- name: Install packaging (python 3.8)
if: matrix.python.name == 'cp38'
run: python -m pip install packaging
- name: Check package can be imported (bare install, default numpy)
run: |
mkdir tmp_for_import_checking
cd tmp_for_import_checking
python -c "import lightsim2grid"
python -c "from lightsim2grid import *"
python -c "from lightsim2grid.newtonpf import newtonpf"
python -c "from lightsim2grid.timeSerie import TimeSeriesCPP"
python -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP"
python -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP"
python -c "from lightsim2grid.network import LSGrid"
- name: Check package can be imported (bare install)
if: matrix.python.name != 'cp37' && matrix.python.name != 'cp38'
run: |
cd tmp_for_import_checking
python3 -c "import lightsim2grid"
python3 -c "from lightsim2grid import *"
python3 -c "from lightsim2grid.newtonpf import newtonpf"
python3 -c "from lightsim2grid.timeSerie import TimeSeriesCPP"
python3 -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP"
python3 -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP"
python3 -c "from lightsim2grid.network import LSGrid"
- name: Fix urllib3 (python 3.7)
if: matrix.python.name == 'cp37'
run:
pip install urllib3==1.26.6
# otherwise urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips 26 Jan 2017'
- name: Install grid2op
if: matrix.python.name != 'cp314' || matrix.runner.arch != 'x86_64'
# grid2op does not work on darwin cp34 wheel on macos on x86_64
# probably because of pandapower
run: |
python -m pip install grid2op lxml # lxml missing import see https://github.com/e2nIEE/pandapower/issues/2752
python -m pip freeze
- name: Check extra can be imported can be imported (with grid2op)
if: matrix.python.name != 'cp314' || matrix.runner.arch != 'x86_64'
# grid2op does not work on darwin cp34 wheel on macos on x86_64
# probably because of pandapower
run: |
cd tmp_for_import_checking
python -v -c "from lightsim2grid import LightSimBackend"
python -c "from lightsim2grid.timeSerie import TimeSerie"
python -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysis"
python -c "from lightsim2grid.physical_law_checker import PhysicalLawChecker"
python -c "from lightsim2grid.securityAnalysis import SecurityAnalysis"
python -c "from lightsim2grid.network import init_from_pandapower"
- name: Check LightSimBackend can be used to create env
if: matrix.python.name != 'cp314' || matrix.runner.arch != 'x86_64'
# grid2op does not work on darwin cp34 wheel on macos on x86_64
# probably because of pandapower
run: |
cd tmp_for_import_checking
python -v -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: lightsim2grid-wheel-darwin-${{ matrix.python.name }}-${{ matrix.runner.arch}}
path: dist/*.whl
exotic_build:
# build wheel using emulation for "exotic"things
# see https://github.com/cvxpy/cvxpy/blob/master/.github/workflows/build.yml
name: Build ${{ matrix.runner.name }} ${{ matrix.python.name }} wheel with cibuildwheel
runs-on: ${{ matrix.runner.name }}
strategy:
matrix:
runner:
- {
name: macos-14, # host on arm64
whl_nm: macos_arm64,
cibuildwheel: macos
}
- {
name: windows-2022, # host on x86_64
whl_nm: windows_arm64,
cibuildwheel: windows
}
# - {
# name: ubuntu-latest, # host on x86_64 # takes forever, like 20 mins x 2 at least
# whl_nm: linux_arm64,
# cibuildwheel: linux
# }
python:
# - {
# name: cp38,
# version: '3.8',
# }
- {
name: cp39,
version: '3.9',
}
- {
name: cp310,
version: '3.10',
}
- {
name: cp311,
version: '3.11',
}
- {
name: cp312,
version: '3.12',
}
- {
name: cp313,
version: '3.13',
}
- {
name: cp314,
version: '3.14',
}
exclude:
- python:
name: cp310 # because already done natively above
runner:
name: macos-14
- python:
name: cp311 # because already done natively above
runner:
name: macos-14
- python:
name: cp312 # because already done natively above
runner:
name: macos-14
- python:
name: cp313 # because already done natively above
runner:
name: macos-14
- python:
name: cp314 # because already done natively above
runner:
name: macos-14
- python:
name: cp38 # does not work
runner:
name: windows-2022
env:
RUNNER_OS: ${{ matrix.runner.name }}
PYTHON_VERSION: ${{ matrix.python.version }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
with:
submodules: true
- name: Set up QEMU
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
with:
platforms: all
- name: Compile with cibuildwheel
uses: pypa/cibuildwheel@63fd63b352a9a8bdcc24791c9dbee952ee9a8abc # v3.3.0
env:
CIBW_PLATFORM: "${{ matrix.runner.cibuildwheel}}"
CIBW_BUILD: "${{ matrix.python.name}}-*"
CIBW_ARCHS_LINUX: aarch64
CIBW_ARCHS_MACOS: arm64
CIBW_ARCHS_WINDOWS: ARM64
CIBW_ENVIRONMENT: __O3_OPTIM=1
CIBW_TEST_REQUIRES: grid2op pandapower
CIBW_TEST_SKIP: "*-macosx_arm64 *-win_arm64" # to silence warning "While arm64 wheels can be built on x86_64, they cannot be tested."
CIBW_TEST_COMMAND: >
python -c "import lightsim2grid" &&
python -c "from lightsim2grid import *" &&
python -c "from lightsim2grid.newtonpf import newtonpf" &&
python -c "from lightsim2grid.timeSerie import TimeSeriesCPP, TimeSerie" &&
python -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP, ContingencyAnalysis" &&
python -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP, SecurityAnalysis" &&
python -c "from lightsim2grid.network import LSGrid, init_from_pandapower" &&
python -c "from lightsim2grid import LightSimBackend" &&
python -c "from lightsim2grid.physical_law_checker import PhysicalLawChecker"
- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: lightsim2grid-wheel-exotic-${{ matrix.runner.whl_nm}}-${{ matrix.python.name }}
path: ./wheelhouse/*.whl
test_cmake_standalone:
name: Test standalone cmake build — ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-2022, macos-14]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup MSVC (windows)
if: runner.os == 'Windows'
uses: bus1/cabuild/action/msdevshell@e22aba57d6e74891d059d66501b6b5aed8123c4d
with:
architecture: x64
- name: Configure + build lightsim2grid_core
run: |
cmake -S src/core -B _build_core -DCMAKE_BUILD_TYPE=Release
cmake --build _build_core --config Release
- name: Install
run: cmake --install _build_core --prefix _install --config Release
- name: Verify installed layout (unix)
if: runner.os != 'Windows'
run: |
ls _install/lib/*lightsim2grid_core* || ls _install/lib64/*lightsim2grid_core*
ls _install/include/lightsim2grid/LSGrid.hpp
ls _install/lib/cmake/lightsim2grid_core/lightsim2grid_coreConfig.cmake
- name: Verify installed layout (windows)
if: runner.os == 'Windows'
shell: bash
run: |
ls _install/lib/lightsim2grid_core* || ls _install/bin/lightsim2grid_core*
ls _install/include/lightsim2grid/LSGrid.hpp
ls _install/lib/cmake/lightsim2grid_core/lightsim2grid_coreConfig.cmake
- name: Build minimal consumer via find_package
shell: bash
run: |
mkdir -p _test_consumer
cat > _test_consumer/CMakeLists.txt << 'EOF'
cmake_minimum_required(VERSION 3.15)
project(consumer CXX)
set(CMAKE_CXX_STANDARD 14)
find_package(lightsim2grid_core CONFIG REQUIRED)
add_executable(consumer consumer.cpp)
target_link_libraries(consumer PRIVATE lightsim2grid::core)
EOF
cat > _test_consumer/consumer.cpp << 'EOF'
#include <AlgorithmRegistry.hpp>
int main() { auto& r = ls2g::AlgorithmRegistry::instance(); return r.available_algorithm_names().empty() ? 1 : 0; }
EOF
cmake -S _test_consumer -B _build_consumer \
-DCMAKE_PREFIX_PATH="$(pwd)/_install" \
-DCMAKE_BUILD_TYPE=Release
cmake --build _build_consumer --config Release
test_plugin_against_installed:
name: Test plugin against pip-installed — ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-2022, macos-14]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Setup MSVC (windows)
if: runner.os == 'Windows'
uses: bus1/cabuild/action/msdevshell@e22aba57d6e74891d059d66501b6b5aed8123c4d
with:
architecture: x64
- name: Install lightsim2grid
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements_compile_ci.txt
python -m pip install -v . --no-build-isolation
- name: Build plugin via get_cmake_dir()
shell: bash
run: |
mkdir -p _tmp_cmake_dir
LS2G_CMAKE=$(cd _tmp_cmake_dir && python -c "import lightsim2grid; print(lightsim2grid.get_cmake_dir())")
cmake -S examples/external_algorithm -B examples/external_algorithm/build \
-DLIGHTSIM2GRID_CMAKE_DIR="$LS2G_CMAKE" \
-DCMAKE_BUILD_TYPE=Release
cmake --build examples/external_algorithm/build --config Release
- name: Run plugin test
run: python examples/external_algorithm/test_plugin.py
- name: Run plugin registration unittests (against the installed package)
shell: bash
# Run from the scratch dir so `import lightsim2grid` resolves to the
# pip-installed package, not the source tree (which has no built
# extension). LS2G_TEST_PLUGIN_DIR points the tests at the plugin built
# above; the finders pick the right per-platform file name themselves.
working-directory: _tmp_cmake_dir
env:
LS2G_TEST_PLUGIN_DIR: ${{ github.workspace }}/examples/external_algorithm/build
run: |
python -m unittest -v \
lightsim2grid.tests.test_solver_registry \
lightsim2grid.tests.test_plugin_registration
test_klu_strategies:
name: Test KLU detection strategies (Ubuntu)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Python build dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements_compile_ci.txt
# ── Strategy 4: build KLU from SuiteSparse submodule CMakeLists ────────
# Submodule present but no pre-built .a files → CMake strategy 4 triggers
- name: "[Strategy 4] Install lightsim2grid"
run: python -m pip install -v . --no-build-isolation
- name: "[Strategy 4] Assert KLU solver is available"
run: |
mkdir -p _klu_check
cd _klu_check
python -c "
from lightsim2grid.lightsim2grid_cpp import klu_solver_available
assert klu_solver_available, 'KLU solver not available (strategy 4 failed)'
print('Strategy 4 OK: KLU available')
"
- name: "[Strategy 4] Uninstall lightsim2grid"
run: pip uninstall lightsim2grid -y
# ── Strategy 3: pre-built .a files in SuiteSparse submodule ────────────
# `make` compiles KLU static libs; CMake finds them via strategy 3
- name: "[Strategy 3] Compile KLU static libraries"
run: make
- name: "[Strategy 3] Install lightsim2grid"
run: python -m pip install -v . --no-build-isolation
- name: "[Strategy 3] Assert KLU solver is available"
run: |
cd _klu_check
python -c "
from lightsim2grid.lightsim2grid_cpp import klu_solver_available
assert klu_solver_available, 'KLU solver not available (strategy 3 failed)'
print('Strategy 3 OK: KLU available')
"
- name: "[Strategy 3] Uninstall lightsim2grid"
run: pip uninstall lightsim2grid -y
- name: "[Strategy 3] Clean compiled KLU static libraries"
run: make distclean
# ── Strategy 1: system-wide KLU via apt ────────────────────────────────
# libsuitesparse-dev on Ubuntu 24.04 ships CMake config files → strategy 1
# SuiteSparse submodule removed so strategies 3 & 4 cannot interfere
- name: "[Strategy 1] Install libsuitesparse-dev"
run: sudo apt-get install -y libsuitesparse-dev
- name: "[Strategy 1] Remove SuiteSparse submodule"
run: rm -rf SuiteSparse
- name: "[Strategy 1] Install lightsim2grid"
run: python -m pip install -v . --no-build-isolation
- name: "[Strategy 1] Assert KLU solver is available"
run: |
cd _klu_check
python -c "
from lightsim2grid.lightsim2grid_cpp import klu_solver_available
assert klu_solver_available, 'KLU solver not available (strategy 1 failed)'
print('Strategy 1 OK: KLU available')
"
test_march_native:
# -march=native is a supported opt-in build flag (see benchmarks/env_compile_all.sh)
# that release wheels do not use, so plain CI builds never exercise it. It changes
# which SIMD ISA Eigen sees enabled (__AVX__, __AVX2__, ...) in each translation
# unit; lightsim2grid_core and lightsim2grid_cpp (the pybind11 bindings) are two
# separate shared libraries, so both must see the identical flag -- otherwise an
# Eigen object allocated in one and freed in the other computes a different
# alignment offset, corrupting the heap ("double free or corruption") the first
# time a function's return value crosses the module boundary (e.g. any pandapower
# -> LightSimBackend conversion, or a forecast-backend copy). Regression test for
# that class of bug: env creation reliably crashed within seconds before the fix.
name: Test -march=native build (Ubuntu)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements_compile_ci.txt
python -m pip install grid2op pandapower lxml
- name: Build lightsim2grid with -march=native
run: __COMPILE_MARCHNATIVE=1 __O3_OPTIM=1 python -m pip install -v . --no-build-isolation
- name: Create + reset a LightSimBackend env (exercises the core<->bindings Eigen boundary)
run: |
mkdir -p _march_native_check
cd _march_native_check
python -c "
import warnings
from grid2op import make
from grid2op.Parameters import Parameters
from lightsim2grid import LightSimBackend
param = Parameters()
param.init_from_dict({'NO_OVERFLOW_DISCONNECTION': True, 'ENV_DC': True, 'FORECAST_DC': True})
with warnings.catch_warnings():
warnings.filterwarnings('ignore')
env = make('l2rpn_case14_sandbox', backend=LightSimBackend(), param=param, test=True)
env.reset()
print('OK: env created and reset under -march=native without crashing')
"
package:
name: Package wheels
runs-on: ubuntu-latest
needs: [exotic_build, macos_build_37_, windows_build, manylinux_build]
steps:
- name: Download wheels
uses: actions/download-artifact@v4
with:
path: download
- name: Verify wheel and sdist count
run: |
WHEEL_COUNT=$(find download/ -name "*.whl" | wc -l | tr -d ' ')
SDIST_COUNT=$(find download/ -name "*.tar.gz" | wc -l | tr -d ' ')
echo "Found ${WHEEL_COUNT} wheel(s), expected ${{ env.EXPECTED_WHEELS }}."
echo "Found ${SDIST_COUNT} sdist(s), expected ${{ env.EXPECTED_SDIST }}."
if [ "${WHEEL_COUNT}" -ne "${{ env.EXPECTED_WHEELS }}" ] || \
[ "${SDIST_COUNT}" -ne "${{ env.EXPECTED_SDIST }}" ]; then
echo "::error::Wheel count mismatch: found ${WHEEL_COUNT} wheels \
and ${SDIST_COUNT} sdist(s), expected ${{ env.EXPECTED_WHEELS }} wheels \
and ${{ env.EXPECTED_SDIST }} sdist(s). A Python version was probably \
added or removed from the build matrix without updating EXPECTED_WHEELS, \
or one of the build jobs silently failed and produced no wheel. \
Fix the matrix and the EXPECTED_WHEELS constant together — this mismatch \
will prevent the PyPI release workflow (publish.yml) from running."
echo ""
echo "--- Wheels found ---"
find download/ -name "*.whl" | sort
echo "--- Sdists found ---"
find download/ -name "*.tar.gz" | sort
exit 1
fi
echo "✓ All ${{ env.EXPECTED_WHEELS }} wheels and ${{ env.EXPECTED_SDIST }} sdist accounted for."
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: lightsim2grid-wheels
retention-days: 90
path: |
download/**/*.whl
download/**/*.tar.gz