Skip to content

Commit c290f95

Browse files
authored
Merge pull request #86 from samrensenhouse/github_action_wheels
GitHub action wheels
2 parents f492d41 + c42cffd commit c290f95

3 files changed

Lines changed: 192 additions & 103 deletions

File tree

.github/workflows/build-wheels.yml

Lines changed: 98 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,38 @@
1-
name: Build Wheels
1+
name: Build wheels
22

3-
on: [push, pull_request]
3+
on:
4+
workflow_dispatch:
45

56
jobs:
6-
build_toolkit_wheels:
7-
name: Build MacOS python 3.8
8-
runs-on: macos-10.15
9-
defaults:
10-
run:
11-
working-directory: ./owa-epanet
7+
build_wheels:
8+
name: Build wheel for cp${{ matrix.python }}-${{ matrix.platform_id }}
9+
runs-on: ${{ matrix.os }}
10+
strategy:
11+
fail-fast: false
12+
matrix:
13+
os: [ windows-latest, ubuntu-latest, macos-latest ]
14+
python: [ 36, 37, 38, 39, 310]
15+
bitness: [ 32, 64 ]
16+
include:
17+
# Run 32 and 64 bit version in parallel for Linux and Windows
18+
- os: windows-latest
19+
bitness: 64
20+
platform_id: win_amd64
21+
- os: windows-latest
22+
bitness: 32
23+
platform_id: win32
24+
- os: ubuntu-latest
25+
bitness: 64
26+
platform_id: manylinux_x86_64
27+
- os: macos-latest
28+
bitness: 64
29+
platform_id: macosx_x86_64
30+
exclude:
31+
- os: macos-latest
32+
bitness: 32
33+
# This build was broken on OpenMP so is excluded for now
34+
- os: ubuntu-latest
35+
bitness: 32
1236

1337
steps:
1438
- name: Checkout repo
@@ -18,24 +42,77 @@ jobs:
1842

1943
- name: Install Python
2044
uses: actions/setup-python@v2
45+
46+
- uses: ilammy/msvc-dev-cmd@v1
47+
if: startsWith(matrix.os, 'windows')
48+
49+
- name: Install cibuildwheel
50+
run: python -m pip install cibuildwheel==2.3.1
51+
52+
- name: Build wheels
53+
run: python -m cibuildwheel --output-dir wheelhouse owa-epanet
54+
env:
55+
CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform_id }}
56+
CIBW_BEFORE_ALL_LINUX: git submodule update --init && yum install swig -y
57+
CIBW_BEFORE_ALL_WINDOWS: git submodule update && choco install swig
58+
CIBW_BEFORE_ALL_MACOS: git submodule update && brew install swig ninja libomp
59+
CIBW_BEFORE_BUILD: pip install scikit-build==0.11.1 cmake==3.18.4
60+
CIBW_BUILD_VERBOSITY: 1
61+
CIBW_TEST_COMMAND: pytest {package}
62+
CIBW_BEFORE_TEST: pip install scikit-build==0.11.1 cmake==3.18.4
63+
CIBW_TEST_REQUIRES: pytest
64+
CIBW_TEST_SKIP: "*-win32 *-manylinux_i686"
65+
66+
- name: Store artifacts
67+
uses: actions/upload-artifact@v2
2168
with:
22-
python-version: 3.8
69+
path: ./wheelhouse/*.whl
70+
71+
72+
build_sdist:
73+
name: Build source distribution
74+
runs-on: ubuntu-latest
75+
steps:
76+
- uses: actions/checkout@v2
77+
with:
78+
submodules: true
2379

24-
- name: Install required system packages
25-
run: brew install swig
80+
- name: Fix submodules
81+
run: |
82+
cd owa-epanet
83+
git submodule update
84+
85+
- uses: actions/setup-python@v2
86+
name: Install Python
87+
with:
88+
python-version: '3.8'
2689

27-
- name: Build wheel
90+
- name: Install dependencies
2891
run: |
29-
pip install scikit-build
30-
python setup.py bdist_wheel
92+
sudo apt update
93+
sudo apt install swig -y
94+
pip install scikit-build==0.11.1 cmake==3.18.4
3195
32-
- name: Test wheel
96+
- name: Build sdist
3397
run: |
34-
pip install pytest
35-
pip install --no-index --find-links=./dist owa-epanet
36-
pytest
98+
cd owa-epanet
99+
python setup.py sdist
37100
38-
- name: Upload artifacts
39-
uses: actions/upload-artifact@v2
101+
- uses: actions/upload-artifact@v2
102+
with:
103+
path: owa-epanet/dist/*.tar.gz
104+
105+
upload_pypi:
106+
needs: [ build_wheels, build_sdist ]
107+
runs-on: ubuntu-latest
108+
109+
steps:
110+
- uses: actions/download-artifact@v2
111+
with:
112+
name: artifact
113+
path: dist
114+
115+
- uses: pypa/gh-action-pypi-publish@v1.4.2
40116
with:
41-
path: owa-epanet/dist/*.whl
117+
user: __token__
118+
password: ${{ secrets.PYPI_API_TOKEN }}

owa-epanet/CMakeLists.txt

Lines changed: 81 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,104 @@
11
cmake_minimum_required(VERSION 3.8)
22

3-
project(OWA-EPANET)
3+
project(owa-epanet)
4+
set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE})
45

56
if(SKBUILD)
67
message(STATUS "The project is built using scikit-build")
78
endif()
89

9-
find_package(PythonLibs 3 REQUIRED)
10-
find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} REQUIRED)
11-
# If find_package() has difficulty finding the appropriate python
12-
# directories and libraries (especially in Windows with multiple
13-
# versions of python) set them manually as in the next three lines
14-
# below (and comment out the above two find_package() lines):
15-
# set(PYTHON_EXECUTABLE "c:/python/python38/python.exe")
16-
# set(PYTHON_INCLUDE_PATH "c:/python/python38/include")
17-
# set(PYTHON_LIBRARIES "c:/python/python38/libs/python38.lib")
10+
# Setup python
11+
if(NOT MSVC)
12+
find_package (Python3 ${PYTHON_VERSION_STRING} COMPONENTS Interpreter Development.Module EXACT REQUIRED)
13+
else()
14+
find_package (Python3 ${PYTHON_VERSION_STRING} COMPONENTS Interpreter Development EXACT REQUIRED)
15+
endif()
1816

17+
# Setup swig
1918
find_package(SWIG REQUIRED)
19+
cmake_policy(SET CMP0078 NEW)
20+
cmake_policy(SET CMP0086 NEW)
2021
include(${SWIG_USE_FILE})
2122
set(CMAKE_SWIG_FLAGS -py3)
2223

2324
message("PYTHONLIBS_VERSION_STRING: ${PYTHONLIBS_VERSION_STRING}")
2425
message("CMAKE_SWIG_FLAGS: ${CMAKE_SWIG_FLAGS}")
2526

26-
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
27-
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
28-
INCLUDE_DIRECTORIES(EPANET/include)
29-
INCLUDE_DIRECTORIES(EPANET/src/outfile/include)
30-
31-
SET(CMAKE_SWIG_FLAGS "")
32-
33-
SET_SOURCE_FILES_PROPERTIES(toolkit.i PROPERTIES CPLUSPLUS ON)
34-
SET_SOURCE_FILES_PROPERTIES(toolkit.i PROPERTIES SWIG_FLAGS "-includeall")
35-
36-
37-
# build the EPANET library
27+
# Build the EPANET library
3828
ADD_SUBDIRECTORY(EPANET)
3929

40-
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
41-
42-
SWIG_ADD_LIBRARY( toolkit LANGUAGE python SOURCES wrapper/toolkit.i )
43-
set_property(SOURCE toolkit.i PROPERTY USE_LIBRARY_INCLUDE_DIRECTORIES TRUE)
44-
set_property(TARGET epanet2 PROPERTY SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE)
45-
SWIG_LINK_LIBRARIES(toolkit epanet2)
30+
# Set up rpath on MacOS and Linux
31+
if(APPLE)
32+
set(PACKAGE_RPATH "@loader_path")
33+
else()
34+
set(PACKAGE_RPATH "$ORIGIN")
35+
endif()
4636

47-
SWIG_LINK_LIBRARIES(toolkit ${PYTHON_LIBRARIES})
48-
set_property(TARGET _toolkit PROPERTY INSTALL_RPATH "$ORIGIN")
4937

50-
#SWIG_ADD_LIBRARY( output LANGUAGE python SOURCES wrapper/output.i )
51-
#SET_PROPERTY( SOURCE output.i PROPERTY USE_LIBRARY_INCLUDE_DIRECTORIES TRUE )
52-
#SET_PROPERTY( TARGET epanet-output PROPERTY SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE )
53-
#SWIG_LINK_LIBRARIES( output epanet-output)
54-
#SWIG_LINK_LIBRARIES( output ${PYTHON_LIBRARIES} )
55-
#SET_PROPERTY( TARGET _output PROPERTY INSTALL_RPATH "$ORIGIN" )
38+
# Include files for swig
39+
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
40+
INCLUDE_DIRECTORIES(EPANET/include)
41+
INCLUDE_DIRECTORIES(EPANET/src/outfile/include)
5642

57-
IF (APPLE)
58-
set_target_properties(_toolkit PROPERTIES INSTALL_RPATH "@loader_path")
59-
ENDIF (APPLE)
6043

61-
install(TARGETS _toolkit LIBRARY DESTINATION packages/epanet)
44+
# Allow target_include_directories to be used later
45+
set_property(SOURCE wrapper/toolkit.i
46+
PROPERTY
47+
USE_TARGET_INCLUDE_DIRECTORIES TRUE
48+
)
49+
set_property(TARGET epanet2
50+
PROPERTY
51+
USE_TARGET_INCLUDE_DIRECTORIES TRUE
52+
)
53+
54+
# Create cmake target
55+
swig_add_library(toolkit
56+
TYPE
57+
MODULE
58+
LANGUAGE
59+
python
60+
SOURCES
61+
wrapper/toolkit.i
62+
)
63+
64+
target_include_directories(toolkit
65+
PUBLIC
66+
${Python3_INCLUDE_DIRS}
67+
)
68+
69+
target_link_options(toolkit
70+
PUBLIC
71+
$<$<BOOL:${APPLE}>:-undefined dynamic_lookup>
72+
)
73+
74+
75+
76+
swig_link_libraries(toolkit
77+
PUBLIC
78+
$<$<BOOL:$<C_COMPILER_ID:MSVC>>:Python3::Module>
79+
epanet2
80+
)
81+
82+
set_target_properties(toolkit
83+
PROPERTIES
84+
SWIG_COMPILE_DEFINITIONS EXPORT_OUT_API
85+
MACOSX_RPATH TRUE
86+
SKIP_BUILD_RPATH FALSE
87+
BUILD_WITH_INSTALL_RPATH FALSE
88+
INSTALL_RPATH "${PACKAGE_RPATH}"
89+
INSTALL_RPATH_USE_LINK_PATH TRUE
90+
)
91+
92+
install(TARGETS toolkit LIBRARY DESTINATION packages/epanet)
6293

6394
add_custom_command(
64-
TARGET _toolkit POST_BUILD
65-
COMMAND ${CMAKE_COMMAND} -E copy
66-
${CMAKE_CURRENT_BINARY_DIR}/toolkit.py
67-
${CMAKE_CURRENT_BINARY_DIR}/../../../packages/epanet/toolkit.py)
68-
69-
IF(WIN32)
70-
add_custom_command(
71-
TARGET _toolkit POST_BUILD
72-
COMMAND ${CMAKE_COMMAND} -E copy
73-
${CMAKE_CURRENT_BINARY_DIR}/lib/_toolkit.pyd
74-
${CMAKE_CURRENT_BINARY_DIR}/../../../packages/epanet/_toolkit.pyd)
75-
add_custom_command(
76-
TARGET _toolkit POST_BUILD
77-
COMMAND ${CMAKE_COMMAND} -E copy
78-
${CMAKE_CURRENT_BINARY_DIR}/bin/epanet2.dll
79-
${CMAKE_CURRENT_BINARY_DIR}/../../../packages/epanet/epanet2.dll)
80-
ELSE(True)
81-
add_custom_command(
82-
TARGET _toolkit POST_BUILD
83-
COMMAND ${CMAKE_COMMAND} -E copy
84-
${CMAKE_CURRENT_BINARY_DIR}/lib/libepanet2.*
85-
${CMAKE_CURRENT_BINARY_DIR}/../../../packages/epanet/)
86-
ENDIF(WIN32)
87-
88-
89-
90-
#add_custom_command(
91-
# TARGET _toolkit POST_BUILD
92-
# COMMAND ${CMAKE_COMMAND} -E copy
93-
# ${CMAKE_CURRENT_BINARY_DIR}/output.py
94-
# ${CMAKE_CURRENT_BINARY_DIR}/../../../packages/epanet/output.py)
95-
96-
#add_custom_command(
97-
# TARGET _toolkit POST_BUILD
98-
# COMMAND ${CMAKE_COMMAND} -E copy
99-
# ${CMAKE_CURRENT_BINARY_DIR}/lib/libepanet-output.*
100-
# ${CMAKE_CURRENT_BINARY_DIR}/../../../packages/epanet/)
95+
TARGET toolkit
96+
POST_BUILD
97+
COMMAND ${CMAKE_COMMAND} -E copy
98+
"${CMAKE_CURRENT_BINARY_DIR}/toolkit.py"
99+
$<$<BOOL:${WIN32}>:${CMAKE_CURRENT_BINARY_DIR}/_toolkit.pyd>
100+
$<$<BOOL:${WIN32}>:${CMAKE_CURRENT_BINARY_DIR}/bin/epanet2.dll>
101+
$<$<NOT:$<BOOL:${WIN32}>>:${CMAKE_CURRENT_BINARY_DIR}/lib/libepanet2.*>
102+
${CMAKE_SOURCE_DIR}/packages/epanet
103+
)
104+

owa-epanet/test/test_owa_epanet.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@
1515

1616

1717
def clean_dir():
18+
def safe_delete(filename):
19+
try:
20+
os.remove(filename)
21+
except PermissionError:
22+
pass
1823
if os.path.exists('report.rpt'):
19-
os.remove('report.rpt')
24+
safe_delete('report.rpt')
2025
if os.path.exists('output.out'):
21-
os.remove('output.out')
26+
safe_delete('output.out')
2227
if os.path.exists('saved_inp_file.inp'):
23-
os.remove('saved_inp_file.inp')
28+
safe_delete('saved_inp_file.inp')
2429

2530

2631
def test_create_project():
@@ -236,8 +241,9 @@ def test_water_age_sim():
236241
en.closeQ(ph=epanet_proj)
237242
en.closeH(ph=epanet_proj)
238243
en.close(ph=epanet_proj)
239-
assert age_list[26] == [1.0, 2.2141675704376946, 12.939125434025273, 24.44152992466322, 13.174235412569542,
240-
24.441519659540887, 15.679376648181817, 21.97064181429266, 19.048343501261524, 1.0]
244+
assert age_list[26] == pytest.approx(
245+
[1.0, 2.2141675704376946, 12.939125434025273, 24.44152992466322, 13.174235412569542,
246+
24.441519659540887, 15.679376648181817, 21.97064181429266, 19.048343501261524, 1.0])
241247
clean_dir()
242248

243249

@@ -324,6 +330,7 @@ def test_setnodevalue():
324330
assert tank_level_list ==[121.0]
325331
clean_dir()
326332

333+
327334
def test_setcurve():
328335
def make_array(values):
329336
dbl_arr = en.doubleArray(len(values))
@@ -341,6 +348,7 @@ def make_array(values):
341348
count = en.getcurvelen(ph=epanet_proj, index=curve_index)
342349
assert count == 5
343350

351+
344352
def test_coords():
345353
epanet_proj = en.createproject()
346354
en.open(ph=epanet_proj, inpFile=example_1_path, rptFile='report.rpt', outFile='output.out')

0 commit comments

Comments
 (0)