Add github action to build python wheels (including python 3.9 and 3.10) (#2097)

* Fix build error: `src/Backends/IF97/IF97Backend.h:54:34: error: call of overloaded ‘abs(double)’ is ambiguous`

Found with the manylinux_2_24_x86_64

gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516

* Register MSVC 2019 and 2022 in setup.py

* setup.py: when calling cmake, build in parallel

* Enable using Env variables instead of passing them as args to setup.py

* Github actions for linux: try 1

* use actions/checkout@v3 for submodules

* mod setup.py:; typo

* Random shot for cibuildwheel for all platforms

* I thought package_dir was a flag, but it's positional

* typo in cmake_compiler

* add cython to setup_requires

* try a pryproject.toml to install cython

* try more requirements?

* pywin32 only found on win32 I guess

* Try with CIBW_BEFORE_BUILD instead

* try to enable msvc via vcvarsall on windows, and pass MACOSX_DEPLOYMENT_TARGET

* more tweaks for windoze

* disable tests for now (fails on windows)

* tweak mac again: it seems mac doesn't understand a C++ lambda, so like it's using pre C++11

* tweak

* try 10.15 for mac...

* try to  force C++11 since mac picks up the path where lambdas are used...

* Move back down to 10.9 now that C++11 is enabled and it works on mac, it should be enough

* Try to debug win32

* Enable part of the upload step (minus the upload) to list the wheels

* try to allow win32 to fail for now (instead of plain disabling)

* Disable the python_linux.yml workflow, so cibuildwheels works fine.

* Adjust the upload step to point to the right folder

* make LGTM python happy
This commit is contained in:
Julien Marrec
2022-03-31 15:26:31 +02:00
committed by GitHub
parent 072f828e3e
commit 149a40d88b
5 changed files with 364 additions and 20 deletions

View File

@@ -0,0 +1,71 @@
name: Python Linux
on:
push:
branches: [ master, develop, actions_pypi ]
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
pull_request:
branches: [ master ]
jobs:
python_bindings:
name: Build ${{ matrix.name }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: 3.10.x
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install twine
- name: Build manylinux Python wheels
uses: RalfG/python-wheels-manylinux-build@v0.4.2
with:
package-path: wrappers/Python/
pre-build-command: 'export COOLPROP_CMAKE=default,64'
python-versions: 'cp36-cp36m cp37-cp37m cp38-cp38 cp39-cp39 cp310-cp310'
build-requirements: 'cython'
pip-wheel-args: '-w ./dist --verbose'
- name: Zip the wheels to maintain case sensitivy and file permissions
working-directory: ./wrappers/Python/
shell: bash
run: |
tar -cvzf CoolProp-Linux_wheels.tar.gz dist/
- name: Upload .whl to artifact
uses: actions/upload-artifact@v2
with:
name: CoolProp-Linux_wheels
path: ./wrappers/Python/CoolProp-Linux_wheels.tar.gz
- name: Publish wheels to (Test)PyPI
# TODO: for now I'm effectively disabling uploading to testpypi on each build
if: contains(github.ref, 'refs/tags')
working-directory: ./wrappers/Python/
env:
TWINE_USERNAME: __token__
run: |
if [[ "$GITHUB_REF" == *"refs/tags"* ]]; then
TWINE_REPOSITORY=pypi
TWINE_PASSWORD=${{ secrets.PYPI_TOKEN }}
else
TWINE_REPOSITORY=testpypi
TWINE_PASSWORD=${{ secrets.TESTPYPI_TOKEN }}
fi;
echo "TWINE_REPOSITORY=$TWINE_REPOSITORY" >> $GITHUB_ENV
echo "TWINE_PASSWORD=$TWINE_PASSWORD" >> $GITHUB_ENV
twine upload dist/*-manylinux*.whl

View File

@@ -0,0 +1,233 @@
name: Python cibuildwheel
on:
push:
branches: [ master, develop, actions_pypi ]
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
pull_request:
branches: [ master ]
jobs:
python_bindings:
name: Build wheel for cp${{ matrix.python }}-${{ matrix.platform_id }}-${{ matrix.manylinux_image }}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.allow_failure }}
strategy:
# Ensure that a wheel builder finishes even if another fails
fail-fast: false
matrix:
include:
# Window 64 bit
# Note: windows-2019 is needed for older Python versions:
# https://github.com/scikit-learn/scikit-learn/issues/22530
- os: windows-2019
python: 38
bitness: 64
platform_id: win_amd64
cmake_compiler: vc16
arch: x64
allow_failure: false
- os: windows-latest
python: 39
bitness: 64
cmake_compiler: vc17
platform_id: win_amd64
arch: x64
allow_failure: false
- os: windows-latest
python: 310
bitness: 64
platform_id: win_amd64
cmake_compiler: vc17
arch: x64
allow_failure: false
# Window 32 bit
- os: windows-latest
python: 38
bitness: 32
platform_id: win32
cmake_compiler: vc17
arch: x86
allow_failure: true
- os: windows-latest
python: 39
bitness: 32
platform_id: win32
cmake_compiler: vc17
arch: x86
allow_failure: true
# Linux 64 bit manylinux2014
- os: ubuntu-latest
python: 37
bitness: 64
platform_id: manylinux_x86_64
manylinux_image: manylinux2014
cmake_compiler: default
allow_failure: false
- os: ubuntu-latest
python: 38
bitness: 64
platform_id: manylinux_x86_64
manylinux_image: manylinux2014
cmake_compiler: default
allow_failure: false
- os: ubuntu-latest
python: 39
bitness: 64
platform_id: manylinux_x86_64
manylinux_image: manylinux2014
cmake_compiler: default
allow_failure: false
- os: ubuntu-latest
python: 310
bitness: 64
platform_id: manylinux_x86_64
manylinux_image: manylinux2014
cmake_compiler: default
allow_failure: false
# MacOS x86_64
- os: macos-latest
bitness: 64
python: 37
platform_id: macosx_x86_64
cmake_compiler: default
allow_failure: false
- os: macos-latest
bitness: 64
python: 38
platform_id: macosx_x86_64
cmake_compiler: default
allow_failure: false
- os: macos-latest
bitness: 64
python: 39
platform_id: macosx_x86_64
cmake_compiler: default
allow_failure: false
- os: macos-latest
bitness: 64
python: 310
platform_id: macosx_x86_64
cmake_compiler: default
allow_failure: false
# MacOS arm64
- os: macos-latest
bitness: 64
python: 38
platform_id: macosx_arm64
cmake_compiler: default
allow_failure: false
- os: macos-latest
bitness: 64
python: 39
platform_id: macosx_arm64
cmake_compiler: default
allow_failure: false
- os: macos-latest
bitness: 64
python: 310
platform_id: macosx_arm64
cmake_compiler: default
allow_failure: false
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: 3.9.x
- name: Setup Deps
shell: bash
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
# C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise
MSVC_DIR=$(cmd.exe /c "vswhere -products * -requires Microsoft.Component.MSBuild -property installationPath -latest")
echo "Latest is: $MSVC_DIR"
echo "MSVC_DIR=$MSVC_DIR" >> $GITHUB_ENV
# add folder containing vcvarsall.bat
echo "$MSVC_DIR\VC\Auxiliary\Build" >> $GITHUB_PATH
fi
- name: Build and test wheels
env:
COOLPROP_CMAKE: ${{ matrix.cmake_compiler}},${{ matrix.bitness }}
CIBW_ENVIRONMENT: COOLPROP_CMAKE=${{ matrix.cmake_compiler }},${{ matrix.bitness }}
MACOSX_DEPLOYMENT_TARGET: 10.9
CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
CIBW_BEFORE_BUILD: pip install setuptools wheel Cython requests jinja2 pyyaml
CIBW_BEFORE_ALL_WINDOWS: call vcvarsall.bat ${{ matrix.arch }}
CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform_id }}
CIBW_ARCHS: all
CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux_image }}
CIBW_MANYLINUX_I686_IMAGE: ${{ matrix.manylinux_image }}
CIBW_TEST_SKIP: "*-macosx_arm64"
# CIBW_TEST_COMMAND: python -c 'from CoolProp.CoolProp import get_global_param_string; print("CoolProp gitrevision:", get_global_param_string("gitrevision"))'
CIBW_BUILD_VERBOSITY: 1
run: |
python -m pip install cibuildwheel
python -m cibuildwheel --output-dir wheelhouse ./wrappers/Python
- name: Store artifacts
uses: actions/upload-artifact@v2
with:
path: wheelhouse/*.whl
upload_python_bindings_to_pypi:
needs: python_bindings
name: Upload to PyPi
runs-on: ubuntu-latest
steps:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9.x
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine requests packaging
mkdir wheels
- name: Download ALL wheels
uses: actions/download-artifact@v2
with:
path: ./wheels
- name: Display structure of downloaded files
working-directory: ./wheels
run: |
ls -R
- name: Publish wheels to (Test)PyPI
# TODO: for now I'm effectively disabling uploading to testpypi on each build
if: contains(github.ref, 'refs/tags')
working-directory: ./wheels/artifact
env:
TWINE_USERNAME: __token__
run: |
if [[ "$GITHUB_REF" == *"refs/tags"* ]]; then
TWINE_REPOSITORY=pypi
TWINE_PASSWORD=${{ secrets.PYPI_TOKEN }}
else
TWINE_REPOSITORY=testpypi
TWINE_PASSWORD=${{ secrets.TESTPYPI_TOKEN }}
fi;
echo "TWINE_REPOSITORY=$TWINE_REPOSITORY" >> $GITHUB_ENV
echo "TWINE_PASSWORD=$TWINE_PASSWORD" >> $GITHUB_ENV
twine upload *.whl

View File

@@ -90,6 +90,9 @@ option (COOLPROP_NO_EXAMPLES
# "On Darwin systems, compile and link with -std=libc++ instead of the default -std=libstdc++"
# ON)
# Force C++11 since lambdas are used in CPStrings.h
set(CMAKE_CXX_STANDARD 11)
# see
# https://stackoverflow.com/questions/52509602/cant-compile-c-program-on-a-mac-after-upgrade-to-mojave
# https://support.enthought.com/hc/en-us/articles/204469410-OS-X-GCC-Clang-and-Cython-in-10-9-Mavericks

View File

@@ -7,6 +7,7 @@
#include "AbstractState.h"
#include "Exceptions.h"
#include <vector>
#include <cmath>
namespace CoolProp {
@@ -44,14 +45,14 @@ public:
this->_rhomass.clear();
this->_hmass.clear();
this->_smass.clear();
this->_phase = iphase_not_imposed;
this->_phase = iphase_not_imposed;
return true;
};
void set_phase() {
double epsilon = 3.3e-5; // IAPWS-IF97 RMS saturated pressure inconsistency
if ((abs(_T - IF97::Tcrit) < epsilon/10.0) && // RMS temperature inconsistency ~ epsilon/10
(abs(_p - IF97::Pcrit) < epsilon)) { // within epsilon of [Tcrit,Pcrit]
if ((std::abs(_T - IF97::Tcrit) < epsilon/10.0) && // RMS temperature inconsistency ~ epsilon/10
(std::abs(_p - IF97::Pcrit) < epsilon)) { // within epsilon of [Tcrit,Pcrit]
_phase = iphase_critical_point; // at critical point
}
else if (_T >= IF97::Tcrit) { // to the right of the critical point
@@ -92,31 +93,31 @@ public:
void update(CoolProp::input_pairs input_pair, double value1, double value2){
double H,S,hLmass,hVmass,sLmass,sVmass;
clear(); //clear the few cached values we are using
switch(input_pair){
case PT_INPUTS:
_p = value1;
_T = value2;
case PT_INPUTS:
_p = value1;
_T = value2;
_Q = -1;
set_phase();
//Two-Phase Check, with PT Inputs:
//Two-Phase Check, with PT Inputs:
if (_phase == iphase_twophase)
throw ValueError(format("Saturation pressure [%g Pa] corresponding to T [%g K] is within 3.3e-3 %% of given p [%Lg Pa]", IF97::psat97(_T), _T, _p));
break;
case PQ_INPUTS:
_p = value1;
case PQ_INPUTS:
_p = value1;
_Q = value2;
if ((_Q < 0) || (_Q > 1))
if ((_Q < 0) || (_Q > 1))
throw CoolProp::OutOfRangeError("Input vapor quality [Q] must be between 0 and 1");
_T = IF97::Tsat97(_p); // ...will throw exception if _P not on saturation curve
_phase = iphase_twophase;
break;
case QT_INPUTS:
_Q = value1;
_T = value2;
if ((_Q < 0) || (_Q > 1))
case QT_INPUTS:
_Q = value1;
_T = value2;
if ((_Q < 0) || (_Q > 1))
throw CoolProp::OutOfRangeError("Input vapor quality [Q] must be between 0 and 1");
_p = IF97::psat97(_T); // ...will throw exception if _P not on saturation curve
_phase = iphase_twophase;
@@ -241,8 +242,8 @@ public:
else if (std::abs(_Q-1) < 1e-10){
return calc_SatVapor(iCalc); // dew point (Q == 1) on Sat. Vapor curve
}
else { // else "inside" bubble ( 0 < Q < 1 )
switch(iCalc){
else { // else "inside" bubble ( 0 < Q < 1 )
switch(iCalc){
case iDmass:
// Density is an inverse phase weighted property, since it's the inverse of specific volume
return 1.0/(_Q/calc_SatVapor(iDmass) + (1.0-_Q)/calc_SatLiquid(iDmass)); break;

View File

@@ -4,6 +4,7 @@ import subprocess, shutil, os, sys, glob, tempfile
from distutils.version import LooseVersion
from distutils.sysconfig import get_config_var
from setuptools.command.build_ext import build_ext
from multiprocessing import cpu_count
def copy_files():
def copytree(old, new):
@@ -105,11 +106,15 @@ if __name__ == '__main__':
i = sys.argv.index(cmake_args[0])
sys.argv.pop(i)
cmake_compiler, cmake_bitness = cmake_args[0].split('cmake=')[1].split(',')
elif os.environ.get('COOLPROP_CMAKE'):
cmake_compiler, cmake_bitness = os.environ.get('COOLPROP_CMAKE').split(',')
else:
if '--cmake-compiler' in sys.argv:
i = sys.argv.index('--cmake-compiler')
sys.argv.pop(i)
cmake_compiler = sys.argv.pop(i)
elif os.environ.get('COOLPROP_CMAKE_COMPILER'):
cmake_compiler = os.environ.get('COOLPROP_CMAKE_COMPILER')
else:
cmake_compiler = ''
@@ -117,6 +122,8 @@ if __name__ == '__main__':
i = sys.argv.index('--cmake-bitness')
sys.argv.pop(i)
cmake_bitness = sys.argv.pop(i)
elif os.environ.get('COOLPROP_CMAKE_BITNESS'):
cmake_bitness = os.environ.get('COOLPROP_CMAKE_BITNESS')
else:
cmake_bitness = ''
@@ -127,6 +134,10 @@ if __name__ == '__main__':
STATIC_LIBRARY_BUILT = False
if USING_CMAKE:
if not cmake_compiler:
# Assume default
cmake_compiler = 'default'
# Always force build since any changes in the C++ files will not force a rebuild
touch('CoolProp/CoolProp.pyx')
@@ -169,6 +180,26 @@ if __name__ == '__main__':
cmake_config_args += ['-G', '"Visual Studio 15 2017 Win64"']
else:
raise ValueError('cmake_bitness must be either 32 or 64; got ' + cmake_bitness)
elif cmake_compiler == 'vc16':
cmake_build_args = ['--config', '"Release"']
if cmake_bitness == '32':
cmake_config_args += ['-G', '"Visual Studio 16 2019"', '-A',
'x86']
elif cmake_bitness == '64':
cmake_config_args += ['-G', '"Visual Studio 16 2019"', '-A',
'x64']
else:
raise ValueError('cmake_bitness must be either 32 or 64; got ' + cmake_bitness)
elif cmake_compiler == 'vc17':
cmake_build_args = ['--config', '"Release"']
if cmake_bitness == '32':
cmake_config_args += ['-G', '"Visual Studio 17 2022"', '-A',
'x86']
elif cmake_bitness == '64':
cmake_config_args += ['-G', '"Visual Studio 17 2022"', '-A',
'x64']
else:
raise ValueError('cmake_bitness must be either 32 or 64; got ' + cmake_bitness)
elif cmake_compiler == 'mingw':
cmake_config_args = ['-G', '"MinGW Makefiles"']
if cmake_bitness == '32':
@@ -180,7 +211,7 @@ if __name__ == '__main__':
elif cmake_compiler == 'default':
cmake_config_args = []
if sys.platform.startswith('win'):
cmake_build_args = ['--config', '"Release"']
cmake_build_args = ['--config', '"Release"']
if cmake_bitness == '32':
cmake_config_args += ['-DFORCE_BITNESS_32=ON']
elif cmake_bitness == '64':
@@ -209,11 +240,15 @@ if __name__ == '__main__':
if not os.path.exists(cmake_build_dir):
os.makedirs(cmake_build_dir)
cmake_call_string = ' '.join(['cmake', '../../../..', '-DCOOLPROP_STATIC_LIBRARY=ON', '-DCMAKE_VERBOSE_MAKEFILE=ON', '-DCMAKE_BUILD_TYPE=Release'] + cmake_config_args)
if 'vc' not in cmake_compiler:
cmake_config_args += ['-DCMAKE_BUILD_TYPE=Release']
cmake_call_string = ' '.join(['cmake', '../../../..', '-DCOOLPROP_STATIC_LIBRARY=ON', '-DCMAKE_VERBOSE_MAKEFILE=ON'] + cmake_config_args)
print('calling: ' + cmake_call_string)
subprocess.check_call(cmake_call_string, shell=True, stdout=sys.stdout, stderr=sys.stderr, cwd=cmake_build_dir)
cmake_build_string = ' '.join(['cmake', '--build', '.'] + cmake_build_args)
cmake_build_string = ' '.join(['cmake', '--build', '.', '-j',
str(cpu_count())] + cmake_build_args)
print('calling: ' + cmake_build_string)
subprocess.check_call(cmake_build_string, shell=True, stdout=sys.stdout, stderr=sys.stderr, cwd=cmake_build_dir)
@@ -448,6 +483,7 @@ if __name__ == '__main__':
"Operating System :: OS Independent",
"Topic :: Software Development :: Libraries :: Python Modules"
],
setup_requires=['Cython'],
**setup_kwargs
)
except BaseException as E: