Make min and max work with MPIBlockVector when some blocks have size 0 #3549
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: GitHub CI | |
on: | |
push: | |
branches: | |
- main | |
pull_request: | |
branches: | |
- main | |
workflow_dispatch: | |
inputs: | |
git-ref: | |
description: Git Hash (Optional) | |
required: false | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
cancel-in-progress: true | |
defaults: | |
run: | |
shell: bash -l {0} | |
env: | |
PYTHONWARNINGS: ignore::UserWarning | |
PYTHON_CORE_PKGS: wheel | |
PYPI_ONLY: z3-solver | |
PYPY_EXCLUDE: scipy numdifftools seaborn statsmodels | |
CACHE_VER: v221013.1 | |
NEOS_EMAIL: [email protected] | |
SRC_REF: ${{ github.head_ref || github.ref }} | |
jobs: | |
lint: | |
name: lint/style-and-typos | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout Pyomo source | |
uses: actions/checkout@v3 | |
- name: Black Formatting Check | |
run: | | |
pip install black | |
black . -S -C --check --diff --exclude examples/pyomobook/python-ch/BadIndent.py | |
- name: Spell Check | |
uses: crate-ci/typos@master | |
with: | |
config: ./.github/workflows/typos.toml | |
build: | |
name: ${{ matrix.TARGET }}/${{ matrix.python }}${{ matrix.other }} | |
needs: lint # the linter job is a prerequisite for PRs | |
runs-on: ${{ matrix.os }} | |
timeout-minutes: 120 | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest, macos-latest, windows-latest] | |
python: [3.7, 3.8, 3.9, '3.10', '3.11'] | |
other: [""] | |
category: [""] | |
include: | |
- os: ubuntu-latest | |
TARGET: linux | |
PYENV: pip | |
- os: macos-latest | |
TARGET: osx | |
PYENV: pip | |
- os: windows-latest | |
TARGET: win | |
PYENV: conda | |
PACKAGES: glpk | |
- os: ubuntu-latest | |
python: 3.9 | |
other: /conda | |
skip_doctest: 1 | |
TARGET: linux | |
PYENV: conda | |
PACKAGES: | |
- os: ubuntu-latest | |
python: 3.8 | |
other: /mpi | |
mpi: 3 | |
skip_doctest: 1 | |
TARGET: linux | |
PYENV: conda | |
PACKAGES: mpi4py openmpi | |
- os: ubuntu-latest | |
python: 3.11 | |
other: /singletest | |
category: "-m 'neos or importtest'" | |
skip_doctest: 1 | |
TARGET: linux | |
PYENV: pip | |
- os: ubuntu-latest | |
python: '3.10' | |
other: /cython | |
setup_options: --with-cython | |
skip_doctest: 1 | |
TARGET: linux | |
PYENV: pip | |
PACKAGES: cython | |
- os: windows-latest | |
python: 3.8 | |
other: /pip | |
skip_doctest: 1 | |
TARGET: win | |
PYENV: pip | |
- os: ubuntu-latest | |
python: 3.7 | |
other: /slim | |
slim: 1 | |
skip_doctest: 1 | |
TARGET: linux | |
PYENV: pip | |
- os: ubuntu-latest | |
python: 3.8 | |
other: /pyutilib | |
TARGET: linux | |
PYENV: pip | |
PACKAGES: pyutilib | |
- os: ubuntu-latest | |
python: pypy-3.9 | |
skip_doctest: 1 | |
TARGET: linux | |
PYENV: pip | |
steps: | |
- name: Checkout Pyomo source | |
uses: actions/checkout@v3 | |
- name: Configure job parameters | |
run: | | |
JOB="${{matrix.TARGET}}/${{matrix.python}}${{matrix.other}}" | |
echo "GHA_JOBNAME=$JOB" | sed 's|/|_|g' >> $GITHUB_ENV | |
if test -z "${{matrix.other}}"; then | |
echo "GHA_JOBGROUP=${{matrix.TARGET}}" >> $GITHUB_ENV | |
else | |
echo "GHA_JOBGROUP=other" >> $GITHUB_ENV | |
fi | |
# Note: pandas 1.0.3 causes gams 29.1.0 import to fail in python 3.8 | |
EXTRAS=tests | |
if test -z "${{matrix.slim}}"; then | |
EXTRAS="$EXTRAS,docs,optional" | |
fi | |
echo "EXTRAS=$EXTRAS" >> $GITHUB_ENV | |
PYTHON_PACKAGES="${{matrix.PACKAGES}}" | |
echo "PYTHON_PACKAGES=$PYTHON_PACKAGES" \ | |
| tr '\n' ' ' | sed 's/ \+/ /g' >> $GITHUB_ENV | |
# Ideally we would cache the conda downloads; however, each cache is | |
# over 850MB, and with 5 python versions, that would consume 4.2 of | |
# the 5 GB GitHub allows. | |
# | |
#- name: Conda package cache | |
# uses: actions/cache@v3 | |
# if: matrix.PYENV == 'conda' | |
# id: conda-cache | |
# with: | |
# path: cache/conda | |
# key: conda-${{env.CACHE_VER}}.0-${{runner.os}}-${{matrix.python}} | |
#- name: Pip package cache | |
# uses: actions/cache@v3 | |
# if: matrix.PYENV == 'pip' | |
# id: pip-cache | |
# with: | |
# path: cache/pip | |
# key: pip-${{env.CACHE_VER}}.0-${{runner.os}}-${{matrix.python}} | |
#- name: OS package cache | |
# uses: actions/cache@v3 | |
# if: matrix.TARGET != 'osx' | |
# id: os-cache | |
# with: | |
# path: cache/os | |
# key: pkg-${{env.CACHE_VER}}.0-${{runner.os}} | |
- name: TPL package download cache | |
uses: actions/cache@v3 | |
if: ${{ ! matrix.slim }} | |
id: download-cache | |
with: | |
path: cache/download | |
key: download-${{env.CACHE_VER}}.0-${{runner.os}} | |
- name: Configure curl | |
run: | | |
CURLRC="$(cat <<EOF | |
retry = 0 | |
max-time = 30 | |
EOF | |
)" | |
echo "$CURLRC" > ${GITHUB_WORKSPACE}/.curlrc | |
echo "$CURLRC" > ${GITHUB_WORKSPACE}/_curlrc | |
echo "CURL_HOME=$GITHUB_WORKSPACE" >> $GITHUB_ENV | |
- name: Update OSX | |
if: matrix.TARGET == 'osx' | |
run: | | |
mkdir -p ${GITHUB_WORKSPACE}/cache/os | |
export HOMEBREW_CACHE=${GITHUB_WORKSPACE}/cache/os | |
# Be cautious running brew update: it can break | |
# setup-python on OSX | |
# brew update | |
# | |
# Notes: | |
# - install glpk | |
# - pyodbc needs: gcc pkg-config unixodbc freetds | |
for pkg in bash pkg-config unixodbc freetds glpk; do | |
brew list $pkg || brew install $pkg | |
done | |
- name: Update Linux | |
if: matrix.TARGET == 'linux' | |
run: | | |
mkdir -p ${GITHUB_WORKSPACE}/cache/os | |
# Notes: | |
# - install glpk | |
# - ipopt needs: libopenblas-dev gfortran liblapack-dev | |
sudo apt-get -o Dir::Cache=${GITHUB_WORKSPACE}/cache/os \ | |
install libopenblas-dev gfortran liblapack-dev glpk-utils | |
sudo chmod -R 777 ${GITHUB_WORKSPACE}/cache/os | |
- name: Update Windows | |
if: matrix.TARGET == 'win' | |
run: | | |
echo "SETUPTOOLS_USE_DISTUTILS=local" >> $GITHUB_ENV | |
- name: Set up Python ${{ matrix.python }} | |
if: matrix.PYENV == 'pip' | |
uses: actions/setup-python@v4 | |
with: | |
python-version: ${{ matrix.python }} | |
- name: Set up Miniconda Python ${{ matrix.python }} | |
if: matrix.PYENV == 'conda' | |
uses: conda-incubator/setup-miniconda@v2 | |
with: | |
auto-update-conda: true | |
python-version: ${{ matrix.python }} | |
channels: conda-forge,gurobi,ibmdecisionoptimization,fico-xpress | |
channel-priority: strict | |
# GitHub actions is very fragile when it comes to setting up various | |
# Python interpreters, expecially the setup-miniconda interface. | |
# Per the setup-miniconda documentation, it is important to always | |
# invoke bash as a login shell ('shell: bash -l {0}') so that the | |
# conda environment is properly activated. However, running within | |
# a login shell appears to foul up the link to python from | |
# setup-python. Further, we have anecdotal evidence that | |
# subprocesses invoked through $(python -c ...) and `python -c ...` | |
# will not pick up the python activated by setup-python on OSX. | |
# | |
# Our solution is to define a PYTHON_EXE environment variable that | |
# can be explicitly called within subprocess calls to reach the | |
# correct interpreter. Note that we must explicitly run in a *non* | |
# login shell to set up the environment variable for the | |
# setup-python environments. | |
- name: Install Python Packages (pip) | |
if: matrix.PYENV == 'pip' | |
shell: bash # DO NOT REMOVE: see note above | |
run: | | |
python -c 'import sys;print(sys.executable)' | |
python -m pip install --cache-dir cache/pip --upgrade pip | |
PYOMO_DEPENDENCIES=`python setup.py dependencies \ | |
--extras "$EXTRAS" | tail -1` | |
PACKAGES="${PYTHON_CORE_PKGS} ${PYTHON_PACKAGES} ${PYOMO_DEPENDENCIES} " | |
if [[ ${{matrix.python}} == pypy* ]]; then | |
EXCLUDE="$PYPY_EXCLUDE $EXCLUDE" | |
fi | |
EXCLUDE=`echo "$EXCLUDE" | xargs` | |
if test -n "$EXCLUDE"; then | |
for WORD in $EXCLUDE; do | |
PACKAGES=${PACKAGES//$WORD / } | |
done | |
fi | |
python -m pip install --cache-dir cache/pip ${PACKAGES} | |
python -m pip install --cache-dir cache/pip pymysql || \ | |
python -m pip install --cache-dir cache/pip pymysql | |
if test -z "${{matrix.slim}}"; then | |
python -m pip install --cache-dir cache/pip cplex docplex \ | |
|| echo "WARNING: CPLEX Community Edition is not available" | |
python -m pip install --cache-dir cache/pip \ | |
-i https://pypi.gurobi.com gurobipy \ | |
|| echo "WARNING: Gurobi is not available" | |
python -m pip install --cache-dir cache/pip xpress \ | |
|| echo "WARNING: Xpress Community Edition is not available" | |
fi | |
python -c 'import sys; print("PYTHON_EXE=%s" \ | |
% (sys.executable,))' >> $GITHUB_ENV | |
echo "" | |
echo "Final pip environment:" | |
python -m pip list | sed 's/^/ /' | |
- name: Install Python packages (conda) | |
if: matrix.PYENV == 'conda' | |
run: | | |
# Set up environment | |
mkdir -p $GITHUB_WORKSPACE/cache/conda | |
conda config --set always_yes yes | |
conda config --set auto_update_conda false | |
conda config --prepend pkgs_dirs $GITHUB_WORKSPACE/cache/conda | |
# Try to install mamba | |
conda install -q -y -n base conda-libmamba-solver || MAMBA_FAILED=1 | |
if test -z "$MAMBA_FAILED"; then | |
echo "*** Activating the mamba environment solver ***" | |
conda config --set solver libmamba | |
fi | |
# Print environment info | |
echo "*** CONDA environment: ***" | |
conda info | |
conda config --show-sources | |
conda config --show channels | |
conda list --show-channel-urls | |
which python | |
python --version | |
# Note: some pypi packages are not available through conda | |
PYOMO_DEPENDENCIES=`python setup.py dependencies \ | |
--extras "$EXTRAS" | tail -1` | |
PACKAGES="${PYTHON_CORE_PKGS} ${PYTHON_PACKAGES} ${PYOMO_DEPENDENCIES} " | |
if [[ ${{matrix.python}} == pypy* ]]; then | |
EXCLUDE="$PYPY_EXCLUDE $EXCLUDE" | |
fi | |
# HACK: Remove problem packages on conda+Linux | |
if test "${{matrix.TARGET}}" == linux; then | |
EXCLUDE="casadi numdifftools pint $EXCLUDE" | |
fi | |
EXCLUDE=`echo "$EXCLUDE" | xargs` | |
if test -n "$EXCLUDE"; then | |
for WORD in $EXCLUDE; do | |
PACKAGES=${PACKAGES//$WORD / } | |
done | |
fi | |
for PKG in $PACKAGES; do | |
if [[ " $PYPI_ONLY " == *" $PKG "* ]]; then | |
PYPI_DEPENDENCIES="$PYPI_DEPENDENCIES $PKG" | |
else | |
CONDA_DEPENDENCIES="$CONDA_DEPENDENCIES $PKG" | |
fi | |
done | |
echo "*** Install Pyomo dependencies ***" | |
conda install -q -y $CONDA_DEPENDENCIES | |
if test -z "${{matrix.slim}}"; then | |
echo "*** Install CPLEX ***" | |
conda install -q -y 'cplex>=12.10' docplex \ | |
|| echo "WARNING: CPLEX Community Edition is not available" | |
echo "*** Install Gurobi ***" | |
conda install -q -y gurobi \ | |
|| echo "WARNING: Gurobi is not available" | |
echo "*** Install Xpress ***" | |
conda install -q -y xpress \ | |
|| echo "WARNING: Xpress Community Edition is not available" | |
for PKG in cyipopt pymumps scip; do | |
echo "*** Install $PKG ***" | |
conda install -q -y $PKG \ | |
|| echo "WARNING: $PKG is not available" | |
done | |
# TODO: This is a hack to stop test_qt.py from running until we | |
# can better troubleshoot why it fails on GHA | |
for QTPACKAGE in qt pyqt; do | |
# Because conda is insane, removing packages can cause | |
# unrelated packages to be updated (breaking version | |
# specifications specified previously, e.g., in | |
# setup.py). There doesn't appear to be a good | |
# workaround, so we will just force-remove (recognizing | |
# that it may break other conda cruft). | |
conda remove --force-remove $QTPACKAGE \ | |
|| echo "$QTPACKAGE not in this environment" | |
done | |
fi | |
# Re-try Pyomo (optional) dependencies with pip | |
if test -n "$PYPI_DEPENDENCIES"; then | |
python -m pip install --cache-dir cache/pip $PYPI_DEPENDENCIES | |
fi | |
# remember this python interpreter | |
python -c 'import sys; print("PYTHON_EXE=%s" \ | |
% (sys.executable,))' >> $GITHUB_ENV | |
# | |
# conda activate puts itself first in the PATH, which overrides | |
# any paths we add through GITHUB_PATH. We will update .profile | |
# to move the local runner paths back to the front (before conda). | |
for profile in $HOME/.profile $HOME/.bash_profile; do | |
if test ! -e $profile; then | |
continue | |
fi | |
echo '' >> $profile | |
echo 'export PATH=`echo "$PATH" \ | |
| tr ":" "\\n" | grep runner | tr "\n" ":"`:`echo "$PATH" \ | |
| tr ":" "\\n" | grep -v runner | tr "\n" ":"`' >> $profile | |
done | |
echo "" | |
echo "Final conda environment:" | |
conda list | sed 's/^/ /' | |
- name: Setup TPL package directories | |
run: | | |
TPL_DIR="${GITHUB_WORKSPACE}/cache/tpl" | |
mkdir -p "$TPL_DIR" | |
DOWNLOAD_DIR="${GITHUB_WORKSPACE}/cache/download" | |
mkdir -p "$DOWNLOAD_DIR" | |
echo "TPL_DIR=$TPL_DIR" >> $GITHUB_ENV | |
echo "DOWNLOAD_DIR=$DOWNLOAD_DIR" >> $GITHUB_ENV | |
- name: Install Ipopt | |
if: ${{ ! matrix.slim }} | |
run: | | |
IPOPT_DIR=$TPL_DIR/ipopt | |
echo "$IPOPT_DIR" >> $GITHUB_PATH | |
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$IPOPT_DIR" >> $GITHUB_ENV | |
mkdir -p $IPOPT_DIR | |
IPOPT_TAR=${DOWNLOAD_DIR}/ipopt.tar.gz | |
if test ! -e $IPOPT_TAR; then | |
echo "...downloading Ipopt" | |
if test "${{matrix.TARGET}}" == osx; then | |
echo "IDAES Ipopt not available on OSX" | |
exit 0 | |
fi | |
URL=https://github.com/IDAES/idaes-ext | |
RELEASE=$(curl --max-time 150 --retry 8 \ | |
-L -s -H 'Accept: application/json' ${URL}/releases/latest) | |
VER=$(echo $RELEASE | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/') | |
URL=${URL}/releases/download/$VER | |
if test "${{matrix.TARGET}}" == linux; then | |
curl --max-time 150 --retry 8 \ | |
-L $URL/idaes-solvers-ubuntu2004-x86_64.tar.gz \ | |
> $IPOPT_TAR | |
else | |
curl --max-time 150 --retry 8 \ | |
-L $URL/idaes-solvers-windows-x86_64.tar.gz \ | |
$URL/idaes-lib-windows-x86_64.tar.gz > $IPOPT_TAR | |
fi | |
fi | |
cd $IPOPT_DIR | |
tar -xzi < $IPOPT_TAR | |
echo "" | |
echo "$IPOPT_DIR" | |
ls -l $IPOPT_DIR | |
- name: Install GAMS | |
if: ${{ ! matrix.slim }} | |
# We install using Powershell because the GAMS installer hangs | |
# when launched from bash on Windows | |
shell: pwsh | |
run: | | |
$GAMS_DIR = "${env:TPL_DIR}/gams" | |
echo "$GAMS_DIR" | ` | |
Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
echo "LD_LIBRARY_PATH=${env:LD_LIBRARY_PATH}:$GAMS_DIR" ` | |
Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
echo "DYLD_LIBRARY_PATH=${env:DYLD_LIBRARY_PATH}:$GAMS_DIR" ` | |
Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
$INSTALLER = "${env:DOWNLOAD_DIR}/gams_install.exe" | |
# We are pinning to 29.1.0 because a license is required for | |
# versions after this in order to run in demo mode. | |
$URL = "https://d37drm4t2jghv5.cloudfront.net/distributions/29.1.0" | |
if ( "${{matrix.TARGET}}" -eq "win" ) { | |
$URL = "$URL/windows/windows_x64_64.exe" | |
} elseif ( "${{matrix.TARGET}}" -eq "osx" ) { | |
$URL = "$URL/macosx/osx_x64_64_sfx.exe" | |
} else { | |
$URL = "$URL/linux/linux_x64_64_sfx.exe" | |
} | |
if (-not (Test-Path "$INSTALLER" -PathType Leaf)) { | |
echo "...downloading GAMS" | |
Invoke-WebRequest -Uri "$URL" -OutFile "$INSTALLER" ` | |
-RetryIntervalSec 30 -MaximumRetryCount 8 -TimeoutSec 150 | |
} | |
echo "...installing GAMS" | |
if ( "${{matrix.TARGET}}" -eq "win" ) { | |
Start-Process -FilePath "$INSTALLER" -ArgumentList ` | |
"/SP- /NORESTART /VERYSILENT /DIR=$GAMS_DIR /NOICONS" ` | |
-Wait | |
} else { | |
chmod 777 $INSTALLER | |
Start-Process -FilePath "$INSTALLER" -ArgumentList ` | |
"-q -d $GAMS_DIR" -Wait | |
mv $GAMS_DIR/*/* $GAMS_DIR/. | |
} | |
echo "" | |
echo "$GAMS_DIR" | |
ls -l $GAMS_DIR | |
- name: Install GAMS Python bindings | |
if: ${{ ! matrix.slim }} | |
run: | | |
GAMS_DIR="${env:TPL_DIR}/gams" | |
py_ver=$($PYTHON_EXE -c 'import sys;v="_%s%s" % sys.version_info[:2] \ | |
;print(v if v != "_27" else "")') | |
if test -e $GAMS_DIR/apifiles/Python/api$py_ver; then | |
echo "Installing GAMS Python bindings" | |
pushd $GAMS_DIR/apifiles/Python/api$py_ver | |
$PYTHON_EXE setup.py install | |
popd | |
fi | |
- name: Install BARON | |
if: ${{ ! matrix.slim }} | |
shell: pwsh | |
run: | | |
$BARON_DIR = "${env:TPL_DIR}/baron" | |
echo "$BARON_DIR" | ` | |
Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
$URL = "https://www.minlp.com/downloads/xecs/baron/current/" | |
if ( "${{matrix.TARGET}}" -eq "win" ) { | |
$INSTALLER = "${env:DOWNLOAD_DIR}/baron_install.exe" | |
$URL += "baron-win64.exe" | |
} elseif ( "${{matrix.TARGET}}" -eq "osx" ) { | |
$INSTALLER = "${env:DOWNLOAD_DIR}/baron_install.zip" | |
$URL += "baron-osx64.zip" | |
} else { | |
$INSTALLER = "${env:DOWNLOAD_DIR}/baron_install.zip" | |
$URL += "baron-lin64.zip" | |
} | |
if (-not (Test-Path "$INSTALLER" -PathType Leaf)) { | |
echo "...downloading BARON ($URL)" | |
Invoke-WebRequest -Uri "$URL" -OutFile "$INSTALLER" ` | |
-RetryIntervalSec 30 -MaximumRetryCount 8 -TimeoutSec 150 | |
} | |
echo "...installing BARON" | |
if ( "${{matrix.TARGET}}" -eq "win" ) { | |
Start-Process -FilePath "$INSTALLER" -ArgumentList ` | |
"/SP- /NORESTART /VERYSILENT /DIR=$BARON_DIR /NOICONS" ` | |
-Wait | |
} else { | |
unzip -q $INSTALLER | |
mv baron-* $BARON_DIR | |
} | |
echo "" | |
echo "$BARON_DIR" | |
ls -l $BARON_DIR | |
- name: Install GJH_ASL_JSON | |
if: ${{ ! matrix.slim && matrix.TARGET != 'win' }} | |
run: | | |
GJH_DIR="$TPL_DIR/gjh" | |
echo "${GJH_DIR}" >> $GITHUB_PATH | |
INSTALL_DIR="${DOWNLOAD_DIR}/gjh" | |
if test ! -e "$INSTALL_DIR/bin"; then | |
mkdir -p "$INSTALL_DIR" | |
INSTALLER="$INSTALL_DIR/gjh_asl_json.zip" | |
URL="https://codeload.github.com/ghackebeil/gjh_asl_json/zip/master" | |
curl --max-time 150 --retry 8 -L $URL > $INSTALLER | |
cd $INSTALL_DIR | |
unzip -q $INSTALLER | |
cd gjh_asl_json-master/Thirdparty | |
./get.ASL | |
cd .. | |
make | |
mv bin "$INSTALL_DIR/bin" | |
fi | |
cp -rp "$INSTALL_DIR/bin" "$GJH_DIR" | |
echo "" | |
echo "$GJH_DIR" | |
ls -l $GJH_DIR | |
- name: Install Pyomo | |
run: | | |
echo "" | |
echo "Clone Pyomo-model-libraries..." | |
URL=https://github.com/Pyomo/pyomo-model-libraries.git | |
git clone -b ${SRC_REF##*/} $URL || git clone -b main $URL | |
echo "" | |
echo "Install Pyomo..." | |
echo "" | |
$PYTHON_EXE setup.py develop ${{matrix.setup_options}} | |
echo "" | |
echo "Set custom PYOMO_CONFIG_DIR" | |
echo "" | |
echo "PYOMO_CONFIG_DIR=${GITHUB_WORKSPACE}/config" >> $GITHUB_ENV | |
# this has to be done after Pyomo is installed because highspy | |
# depends on pyomo's find_library function | |
- name: Install HiGHS | |
if: ${{ ! matrix.slim }} | |
shell: bash | |
run: | | |
$PYTHON_EXE -m pip install --cache-dir cache/pip highspy \ | |
|| echo "WARNING: highspy is not available" | |
- name: Set up coverage tracking | |
run: | | |
if test "${{matrix.TARGET}}" == win; then | |
COVERAGE_BASE=${GITHUB_WORKSPACE}\\.cover | |
else | |
COVERAGE_BASE=${GITHUB_WORKSPACE}/.cover | |
fi | |
COVERAGE_RC=${COVERAGE_BASE}_rc | |
echo "COVERAGE_RCFILE=$COVERAGE_RC" >> $GITHUB_ENV | |
echo "COVERAGE_PROCESS_START=$COVERAGE_RC" >> $GITHUB_ENV | |
cp ${GITHUB_WORKSPACE}/.coveragerc ${COVERAGE_RC} | |
echo "data_file=${COVERAGE_BASE}age" >> ${COVERAGE_RC} | |
SITE_PACKAGES=$($PYTHON_EXE -c "from distutils.sysconfig import \ | |
get_python_lib; print(get_python_lib())") | |
echo "Python site-packages: $SITE_PACKAGES" | |
echo 'import coverage; coverage.process_startup()' \ | |
> ${SITE_PACKAGES}/run_coverage_at_startup.pth | |
- name: Download and install extensions | |
if: ${{ ! matrix.slim }} | |
run: | | |
echo "" | |
echo "Pyomo download-extensions" | |
echo "" | |
pyomo download-extensions || exit 1 | |
echo "" | |
echo "Pyomo build-extensions" | |
echo "" | |
pyomo build-extensions --parallel 2 | |
- name: Report pyomo plugin information | |
run: | | |
echo "$PATH" | |
pyomo help --solvers || exit 1 | |
pyomo help --transformations || exit 1 | |
pyomo help --writers || exit 1 | |
- name: Run Pyomo tests | |
if: matrix.mpi == 0 | |
run: | | |
$PYTHON_EXE -m pytest -v \ | |
-W ignore::Warning ${{matrix.category}} \ | |
pyomo `pwd`/pyomo-model-libraries \ | |
`pwd`/examples/pyomobook --junitxml="TEST-pyomo.xml" | |
- name: Run Pyomo MPI tests | |
if: matrix.mpi != 0 | |
run: | | |
# Manually invoke the DAT parser so that parse_table_datacmds.py | |
# is fully generated by a single process before invoking MPI | |
$PYTHON_EXE -c "from pyomo.dataportal.parse_datacmds import \ | |
parse_data_commands; parse_data_commands(data='')" | |
mpirun -np ${{matrix.mpi}} --oversubscribe pytest -v \ | |
--junit-xml=TEST-pyomo-mpi.xml \ | |
-m "mpi" -W ignore::Warning \ | |
pyomo `pwd`/pyomo-model-libraries | |
- name: Run documentation tests | |
if: matrix.skip_doctest == 0 | |
run: | | |
make -C doc/OnlineDocs doctest -d | |
- name: Process code coverage report | |
run: | | |
coverage combine | |
coverage report -i | |
coverage xml -i | |
- name: Record build artifacts | |
uses: actions/upload-artifact@v3 | |
with: | |
name: ${{github.job}}_${{env.GHA_JOBGROUP}}-${{env.GHA_JOBNAME}} | |
path: | | |
.coverage | |
coverage.xml | |
# In general, do not record test results as artifacts to | |
# manage total artifact storage | |
# TEST-*.xml | |
bare-python-env: | |
name: linux/3.8/bare-env | |
needs: lint # the linter job is a prerequisite for PRs | |
runs-on: ubuntu-latest | |
timeout-minutes: 10 | |
steps: | |
- name: Checkout Pyomo source | |
uses: actions/checkout@v3 | |
- name: Set up Python 3.8 | |
uses: actions/setup-python@v4 | |
with: | |
python-version: 3.8 | |
- name: Install Pyomo | |
run: | | |
echo "" | |
echo "Install Pyomo..." | |
echo "" | |
python setup.py develop | |
echo "" | |
echo "Set custom PYOMO_CONFIG_DIR" | |
echo "" | |
echo "PYOMO_CONFIG_DIR=${GITHUB_WORKSPACE}/config" >> $GITHUB_ENV | |
- name: Report pyomo plugin information | |
run: | | |
echo "$PATH" | |
pyomo help --solvers || exit 1 | |
pyomo help --transformations || exit 1 | |
pyomo help --writers || exit 1 | |
- name: Run Pyomo standalone test | |
run: | | |
echo "" | |
echo "Running standalone Pyomo test" | |
echo "" | |
python `pwd`/pyomo/environ/tests/standalone_minimal_pyomo_driver.py \ | |
|| exit 1 | |
cover: | |
name: process-coverage-${{ matrix.TARGET }} | |
needs: build | |
if: always() # run even if a build job fails | |
runs-on: ${{ matrix.os }} | |
timeout-minutes: 10 | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest, macos-latest, windows-latest] | |
include: | |
- os: ubuntu-latest | |
TARGET: linux | |
- os: macos-latest | |
TARGET: osx | |
- os: windows-latest | |
TARGET: win | |
steps: | |
- name: Checkout Pyomo source | |
uses: actions/checkout@v3 | |
# We need the source for .codecov.yml and running "coverage xml" | |
#- name: Pip package cache | |
# uses: actions/cache@v3 | |
# id: pip-cache | |
# with: | |
# path: cache/pip | |
# key: pip-${{env.CACHE_VER}}.0-${{runner.os}}-3.8 | |
- name: Download build artifacts | |
uses: actions/download-artifact@v3 | |
with: | |
path: artifacts | |
- name: Set up Python 3.8 | |
uses: actions/setup-python@v4 | |
with: | |
python-version: 3.8 | |
- name: Install Python Packages (pip) | |
shell: bash # DO NOT REMOVE: see note above | |
run: | | |
python -c 'import sys;print(sys.executable)' | |
python -m pip install --cache-dir cache/pip --upgrade pip | |
PYOMO_DEPENDENCIES=`python setup.py dependencies \ | |
--extras "tests" | tail -1` | |
python -m pip install --cache-dir cache/pip \ | |
${PYTHON_CORE_PKGS} ${PYOMO_DEPENDENCIES} | |
python -c 'import sys; print("PYTHON_EXE=%s" \ | |
% (sys.executable,))' >> $GITHUB_ENV | |
- name: Install Pyomo | |
run: | | |
echo "" | |
echo "Clone Pyomo-model-libraries..." | |
git clone https://github.com/Pyomo/pyomo-model-libraries.git | |
echo "" | |
echo "Install Pyomo..." | |
echo "" | |
$PYTHON_EXE setup.py develop ${{matrix.setup_options}} | |
echo "" | |
echo "Set custom PYOMO_CONFIG_DIR" | |
echo "" | |
echo "PYOMO_CONFIG_DIR=${GITHUB_WORKSPACE}/config" >> $GITHUB_ENV | |
- name: Generate parse_table_datacmds | |
run: | | |
# Manually invoke the DAT parser so that parse_table_datacmds.py | |
# is generated before running "coverage xml" | |
$PYTHON_EXE -c "from pyomo.dataportal.parse_datacmds import \ | |
parse_data_commands; parse_data_commands(data='')" | |
- name: Update codecov uploader | |
run: | | |
set +e | |
CODECOV="${GITHUB_WORKSPACE}/codecov.sh" | |
echo "CODECOV=$CODECOV" >> $GITHUB_ENV | |
for i in `seq 3`; do | |
echo "Downloading current codecov script (attempt ${i})" | |
curl -L https://codecov.io/bash -o $CODECOV | |
if test $? == 0; then | |
break | |
fi | |
DELAY=$(( RANDOM % 30 + 30)) | |
echo "Pausing $DELAY seconds before re-attempting download" | |
sleep $DELAY | |
done | |
if test ! -e $CODECOV; then | |
echo "Failed to download codecov.sh" | |
exit 1 | |
fi | |
- name: Combine coverage reports | |
if: github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main' | |
run: | | |
set +e | |
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then | |
SHA=$(jq --raw-output .pull_request.head.sha "$GITHUB_EVENT_PATH") | |
else | |
SHA=$GITHUB_SHA | |
fi | |
for ARTIFACT in artifacts/*_*${{matrix.TARGET}}_*; do | |
NAME=`echo $ARTIFACT | cut -d/ -f2` | |
cp -v $ARTIFACT/.coverage .coverage-$NAME | |
done | |
rm -vf .coverage coverage.xml | |
echo "Build: ${{ matrix.TARGET }}/other" | |
echo "" | |
FILES=.coverage-*_other-* | |
coverage combine --debug=dataio $FILES | |
if test ! -e .coverage; then | |
echo "No coverage to upload." | |
else | |
coverage xml || coverage xml -i | |
mv -v coverage.xml coverage-other.xml | |
fi | |
echo "" | |
echo "Build: ${{ matrix.TARGET }}" | |
echo "" | |
FILES=.coverage-*_${{matrix.TARGET}}-* | |
coverage combine --debug=dataio $FILES | |
rm -vf artifacts/*/*.xml | |
if test ! -e .coverage; then | |
echo "No coverage to upload." | |
else | |
coverage xml || coverage xml -i | |
fi | |
- name: Upload codecov reports | |
if: github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main' | |
uses: codecov/codecov-action@v3 | |
with: | |
files: coverage.xml | |
token: ${{ secrets.PYOMO_CODECOV_TOKEN }} | |
name: ${{ matrix.TARGET }} | |
flags: ${{ matrix.TARGET }} | |
fail_ci_if_error: true | |
- name: Upload other coverage reports | |
if: | | |
hashFiles('coverage-other.xml') != '' && | |
(github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main') | |
uses: codecov/codecov-action@v3 | |
with: | |
files: coverage-other.xml | |
token: ${{ secrets.PYOMO_CODECOV_TOKEN }} | |
name: ${{ matrix.TARGET }}/other | |
flags: ${{ matrix.TARGET }},other | |
fail_ci_if_error: true |