From d6d73d4e583c393bf006d363ba6aeaa4b5299094 Mon Sep 17 00:00:00 2001 From: ckaros Date: Sun, 7 Sep 2025 14:29:28 -0400 Subject: [PATCH 01/12] CI/CD Overhaul - implement stable abi (>=3.9) - migrate to scikit-build-core - update cibuildwheel to use native builds for all archs - move shared libs into package dir --- .github/workflows/build_wheel.yml | 65 ++------ .github/workflows/unit_test.yml | 18 +-- swmm-toolkit/CMakeLists.txt | 4 +- swmm-toolkit/pyproject.toml | 55 ++++++- swmm-toolkit/setup.py | 151 ------------------- swmm-toolkit/src/swmm/toolkit/CMakeLists.txt | 51 ++++--- swmm-toolkit/src/swmm/toolkit/__init__.py | 22 +-- 7 files changed, 108 insertions(+), 258 deletions(-) delete mode 100644 swmm-toolkit/setup.py diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 92fa2f8c..d56d7e96 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -27,7 +27,7 @@ jobs: - name: Install Python uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: "3.10" - name: Build wheel run: | @@ -46,12 +46,11 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - pyver: [cp39, cp310, cp311, cp312, cp313] + os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-13, macos-latest] steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: submodules: true @@ -63,19 +62,16 @@ jobs: MACOSX_DEPLOYMENT_TARGET: "11.0" CIBW_TEST_COMMAND: "pytest {package}/tests" CIBW_BEFORE_TEST: pip install -r {package}/test-requirements.txt - # mac needs ninja to build - CIBW_BEFORE_BUILD_MACOS: brew install ninja + + CIBW_ENVIRONMENT_MACOS: | + MACOSX_DEPLOYMENT_TARGET=11.0 + # remove system swig (cmake bug doesn't respect python venv) # https://github.com/swig/swig/issues/2481#issuecomment-1949573105 CIBW_BEFORE_BUILD_LINUX: rm -f $(which swig) && rm -f $(which swig4.0) - # configure cibuildwheel to build native archs ('auto'), and some emulated ones - CIBW_ARCHS_LINUX: x86_64 - CIBW_ARCHS_WINDOWS: AMD64 - CIBW_ARCHS_MACOS: x86_64 arm64 - # only build current supported python: https://devguide.python.org/versions/ - # don't build pypy or musllinux to save build time. TODO: find a good way to support those archs - CIBW_BUILD: ${{matrix.pyver}}-* - CIBW_SKIP: cp38-* pp* *-musllinux* + # skip 3.8 and any free threaded variants + CIBW_SKIP: cp38-* cp3??t-* + CIBW_ARCHS: native # Will avoid testing on emulated architectures # Skip trying to test arm64 builds on Intel Macs CIBW_TEST_SKIP: "*-*linux_{aarch64,ppc64le,s390x} *-macosx_universal2:arm64" @@ -83,45 +79,8 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: wheels-${{ matrix.os }}-${{ matrix.pyver }} + name: wheelhouse_${{ matrix.os }} path: ./wheelhouse/*.whl - build_cross_wheels: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - pyver: [cp39, cp310, cp311, cp312, cp313] - - steps: - - name: Checkout repo - uses: actions/checkout@v5 - with: - submodules: true - - - name: Set up QEMU - if: runner.os == 'Linux' - uses: docker/setup-qemu-action@v2 - with: - platforms: all - - name: Build wheels - uses: pypa/cibuildwheel@v3.1.4 - with: - package-dir: ./swmm-toolkit - env: - # remove system swig (cmake bug doesn't respect python venv) - # https://github.com/swig/swig/issues/2481#issuecomment-1949573105 - CIBW_BEFORE_BUILD_LINUX: rm -f $(which swig) && rm -f $(which swig4.0) - # configure cibuildwheel to build native archs ('auto'), and some emulated ones - CIBW_ARCHS_LINUX: aarch64 - # only build current supported python: https://devguide.python.org/versions/ - # don't build pypy or musllinux to save build time. TODO: find a good way to support those archs - CIBW_BUILD: ${{matrix.pyver}}-* - CIBW_SKIP: cp-*38 pp* *-musllinux* - CIBW_BUILD_VERBOSITY: 1 - - - uses: actions/upload-artifact@v4 - with: - name: wheels-linux-aarch64-${{ matrix.pyver }} - path: ./wheelhouse/*.whl + diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml index 4a830649..a9605b98 100644 --- a/.github/workflows/unit_test.yml +++ b/.github/workflows/unit_test.yml @@ -41,17 +41,17 @@ jobs: - name: Install Python uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.12" - - name: Build wheel in virtual env - env: - MACOSX_DEPLOYMENT_TARGET: "11.0" + - name: Build wheel run: | - python -m venv --clear ./build-env - ${{matrix.activate}} - python -m pip install -r build-requirements.txt - python setup.py bdist_wheel - deactivate + pip install build + python -m build + - name: Upload Wheel + uses: actions/upload-artifact@v4 + with: + name: swmm_toolkit_${{ matrix.os }} + path: ./swmm-toolkit/dist/*.whl - name: Test wheel run: | diff --git a/swmm-toolkit/CMakeLists.txt b/swmm-toolkit/CMakeLists.txt index 99308d30..4f9df55b 100644 --- a/swmm-toolkit/CMakeLists.txt +++ b/swmm-toolkit/CMakeLists.txt @@ -23,9 +23,9 @@ project(swmm-toolkit set(Python_FIND_VIRTUALENV FIRST) #set(CMAKE_FIND_DEBUG_MODE TRUE) if(NOT MSVC) - find_package (Python3 ${PYTHON_VERSION_STRING} COMPONENTS Interpreter Development.Module REQUIRED) + find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module) else() - find_package (Python3 ${PYTHON_VERSION_STRING} COMPONENTS Interpreter Development REQUIRED) + find_package(Python3 REQUIRED COMPONENTS Interpreter Development) endif() #set(CMAKE_FIND_DEBUG_MODE FALSE) diff --git a/swmm-toolkit/pyproject.toml b/swmm-toolkit/pyproject.toml index 538bcb3e..763db0f9 100644 --- a/swmm-toolkit/pyproject.toml +++ b/swmm-toolkit/pyproject.toml @@ -1,10 +1,53 @@ [build-system] requires = [ - "wheel>=0.38.1", - "setuptools>=42", - "scikit-build>=0.13", - "cmake>=3.21", "swig", - "ninja==1.11.1 ; sys_platform == 'darwin'", + "scikit-build-core>=0.4.3", ] -build-backend = "setuptools.build_meta" +build-backend = "scikit_build_core.build" + +[project] +name = "swmm-toolkit" +version = "0.15.5" +description = "PySWMM SWMM Python Toolkit" +readme = { file = "README.md", content-type = "text/markdown" } +license = { text = "CC0" } +authors = [{ name = "See AUTHORS" }] +maintainers = [{ email = "bemcdonnell@gmail.com" }] +keywords = ["swmm5", "swmm", "stormwater", "hydraulics", "hydrology"] +classifiers = [ + "Topic :: Scientific/Engineering", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Operating System :: MacOS", + "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: C", + "Development Status :: 5 - Production/Stable", +] +requires-python = ">=3.9" +dependencies = ["aenum==3.1.11"] +urls = { Homepage = "https://github.com/pyswmm/swmm-python" } + +[[tool.scikit-build.overrides]] +if.platform-system = "win32" +cmake.args = ["-GVisual Studio 17 2022", "-Ax64"] + +[[tool.scikit-build.overrides]] +if.platform-system = "darwin" +cmake.args = ["-GXcode", "-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=11.0"] + +[[tool.scikit-build.overrides]] +if.platform-system = "linux" +cmake.args = ["-GUnix Makefiles"] + +[tool.scikit-build.wheel] +packages = ["src/swmm/toolkit"] +py-api = "cp39" +exclude = ["**/*runswmm*", "**/*.exe", "**/*.cmake", "**/*.h", "**/*.lib", "**/*.i", "**/CMakeLists.txt","toolkit/*", "lib/*", "bin/*", "build-env/*"] + +[tool.scikit-build.sdist] +exclude = ["build-env/*"] diff --git a/swmm-toolkit/setup.py b/swmm-toolkit/setup.py deleted file mode 100644 index 4430e8a2..00000000 --- a/swmm-toolkit/setup.py +++ /dev/null @@ -1,151 +0,0 @@ -# -# setup.py - Setup script for swmm-toolkit python package -# -# Created: Jul 2, 2018 -# Updated: Sep 4, 2025 -# -# Author: See AUTHORS -# -# Suggested Usage: -# python setup.py build -# python setup.py bdist_wheel -# python setup.py sdist -# python setup.py clean -# - -import platform -import subprocess -import pathlib -import os -from skbuild import setup -from setuptools import Command -import sys - -# Determine platform -platform_system = platform.system() - - -class CleanCommand(Command): - ''' Cleans project tree ''' - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - if platform_system == "Windows": - cmd = ['del' '/Q', 'tests\\data\\temp_*.*' '&&' \ - 'rd' '/s/q', '_cmake_test_compile', '_skbuild', 'dist', '.pytest_cache', \ - 'src\\swmm\\toolkit\\swmm_toolkit.egg-info', 'tests\\__pycache__'] - exe = "C:\\Windows\\System32\\cmd.exe" - - elif platform_system == "Linux": - cmd = ["rm -vrf _skbuild/ dist/ **/build .pytest_cache/ **/__pycache__ \ - **/*.egg-info **/data/temp_*.* **/data/en* **/.DS_Store MANIFEST"] - exe = "/bin/bash" - - elif platform_system == "Darwin": - cmd = ['setopt extended_glob nullglob; rm -vrf _skbuild dist **/build .pytest_cache \ - **/__pycache__ **/*.egg-info **/data/(^test_*).* **/data/en* **/.DS_Store MANIFEST'] - exe = '/bin/zsh' - - p = subprocess.Popen(cmd, shell=True, executable=exe) - p.wait() - - -# Set up location of wheel libraries depending on build platform and command -# commands that trigger cmake from skbuild.setuptools_wrap._should_run_cmake -commands_that_trigger_cmake = { - "build", - "build_ext", - "develop", - "install", - "install_lib", - "bdist", - "bdist_dumb", - "bdist_egg", - "bdist_rpm", - "bdist_wininst", - "bdist_wheel", - "test", - } -command = sys.argv[1] if len(sys.argv) > 1 else None -if command in commands_that_trigger_cmake: - swmm_toolkit_dir= "bin" if platform_system == "Windows" else "lib" -else: - swmm_toolkit_dir= "swmm-solver" -package_dir = {"swmm_toolkit" : swmm_toolkit_dir, "swmm.toolkit": "src/swmm/toolkit"} - - -if os.environ.get('SWMM_CMAKE_ARGS') is not None: - cmake_args = os.environ.get('SWMM_CMAKE_ARGS').split() - -# Set Platform specific cmake args here -elif platform_system == "Windows": - cmake_args = ["-GVisual Studio 17 2022","-Ax64"] - -elif platform_system == "Darwin": - cmake_args = ["-GXcode"] - -else: - cmake_args = ["-GUnix Makefiles"] - - -# Filters cmake manifest for wheel build -def exclude_files(cmake_manifest): - print("INFO: processing cmake manifest") - exclude_pats = ('runswmm', '.exe', '.cmake', '.h', '.lib') - return list(filter(lambda name: not (name.endswith(exclude_pats)), cmake_manifest)) - - -# Get the long description from the README file -here = pathlib.Path(__file__).parent.resolve() -long_description = (here / 'README.md').read_text(encoding='utf-8') - -if platform_system == "Darwin": - license_files = ['LICENSE.md', 'extern/license-llvm-openmp.txt'] -else: - license_files = ['LICENSE.md'] - -setup( - name = "swmm-toolkit", - version = "0.16.0", - - packages = ["swmm_toolkit", "swmm.toolkit"], - package_dir = package_dir, - - zip_safe = False, - install_requires = ["aenum>=3.1.11"], - - cmdclass = {"clean": CleanCommand}, - cmake_args = cmake_args, - cmake_process_manifest_hook = exclude_files, - - description='PySWMM SWMM Python Toolkit', - long_description=long_description, - long_description_content_type='text/markdown', - url='https://github.com/pyswmm/swmm-python', - - author='See AUTHORS', - maintainer_email='michael.tryby@gmail.com', - license='CC0', - license_files=license_files, - keywords="swmm5, swmm, stormwater, hydraulics, hydrology", - classifiers=[ - "Topic :: Scientific/Engineering", - "Operating System :: Microsoft :: Windows", - "Operating System :: POSIX :: Linux", - "Operating System :: MacOS", - "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: C", - "Development Status :: 5 - Production/Stable", - ] -) diff --git a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt index 34d735fc..71496f02 100644 --- a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt +++ b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt @@ -15,13 +15,12 @@ # set(CMAKE_SWIG_FLAGS -py3) # Determine filename suffix for python extension +set(CMAKE_MESSAGE_LOG_LEVEL VERBOSE) if(WIN32) - set(LIB_EXT "pyd") + set(PYTHON_SUFFIX ".pyd") else() - set(LIB_EXT "so") + set(PYTHON_SUFFIX ".abi3.so") endif() -set(PYTHON_SUFFIX ".${Python3_SOABI}.${LIB_EXT}") - # Location of package at runtime on MacOS/Linux if(APPLE) @@ -30,11 +29,21 @@ else() set(LIB_ROOT "$ORIGIN") endif() -# Set up rpath on MacOS and Linux -set(PACKAGE_RPATH - "${LIB_ROOT}/../../swmm_toolkit/" -) +# For scikit-build-core, use SKBUILD_PLATLIB_DIR instead of hardcoded paths +if(DEFINED SKBUILD_PLATLIB_DIR) + # scikit-build-core is being used + set(PYTHON_INSTALL_DIR "${SKBUILD_PLATLIB_DIR}/swmm/toolkit") +else() + # Fallback for direct CMake builds or legacy scikit-build + set(PYTHON_INSTALL_DIR "src/swmm/toolkit") +endif() + +if(WIN32) + # Explicitly add the Python libs directory to the linker search path for windows + # Not sure why I need to do this for windows only, but it got the stable ABI to build + link_directories(${Python3_LIBRARY_DIRS}) +endif() ############################################################# #################### OUTPUT TARGET #################### @@ -67,7 +76,6 @@ target_include_directories(output target_link_libraries(output PUBLIC - $<$>:Python3::Module> swmm-output ) @@ -78,8 +86,10 @@ set_target_properties(output MACOSX_RPATH TRUE SKIP_BUILD_RPATH FALSE BUILD_WITH_INSTALL_RPATH FALSE - INSTALL_RPATH "${PACKAGE_RPATH}" + INSTALL_RPATH ${LIB_ROOT} INSTALL_RPATH_USE_LINK_PATH TRUE + # Enable stable ABI for Python 3.9+ + COMPILE_DEFINITIONS "Py_LIMITED_API=0x03090000" ) install( @@ -89,14 +99,17 @@ install( "output_metadata.py" "${CMAKE_CURRENT_BINARY_DIR}/output.py" DESTINATION - "src/swmm/toolkit" + "${PYTHON_INSTALL_DIR}" + COMPONENT python ) install( TARGETS output + swmm-output DESTINATION - "src/swmm/toolkit" + "${PYTHON_INSTALL_DIR}" + COMPONENT python ) ############################################################# @@ -131,7 +144,6 @@ target_include_directories(solver target_link_libraries(solver PUBLIC - $<$>:Python3::Module> swmm5 ) @@ -142,8 +154,10 @@ set_target_properties(solver MACOSX_RPATH TRUE SKIP_BUILD_RPATH FALSE BUILD_WITH_INSTALL_RPATH FALSE - INSTALL_RPATH "${PACKAGE_RPATH}" + INSTALL_RPATH ${LIB_ROOT} INSTALL_RPATH_USE_LINK_PATH TRUE + # Enable stable ABI for Python 3.9+ + COMPILE_DEFINITIONS "Py_LIMITED_API=0x03090000" ) @@ -152,13 +166,16 @@ install( FILES "${CMAKE_CURRENT_BINARY_DIR}/solver.py" DESTINATION - "src/swmm/toolkit" + "${PYTHON_INSTALL_DIR}" + COMPONENT python ) # Stages extension library for package build install( TARGETS solver + swmm5 DESTINATION - "src/swmm/toolkit" -) + "${PYTHON_INSTALL_DIR}" + COMPONENT python +) \ No newline at end of file diff --git a/swmm-toolkit/src/swmm/toolkit/__init__.py b/swmm-toolkit/src/swmm/toolkit/__init__.py index 7ac565cc..ccab9cf0 100644 --- a/swmm-toolkit/src/swmm/toolkit/__init__.py +++ b/swmm-toolkit/src/swmm/toolkit/__init__.py @@ -22,23 +22,5 @@ __date__ = "September 4, 2025" __maintainer__ = "Michael Tryby" -__email__ = "michael.tryby@gmail.com" -__status__ = "Production/Stable" - - -import os -import platform -import sys - - -# Adds directory containing swmm libraries to path -if platform.system() == "Windows": - libdir = os.path.join(os.path.dirname(__file__), "../../swmm_toolkit") - - if hasattr(os, 'add_dll_directory'): - conda_exists = os.path.exists(os.path.join(sys.prefix, 'conda-meta')) - if conda_exists: - os.environ['CONDA_DLL_SEARCH_MODIFICATION_ENABLE'] = "1" - os.add_dll_directory(libdir) - else: - os.environ["PATH"] = libdir + ";" + os.environ["PATH"] +__email__ = "tryby.michael@epa.gov" +__status__ = "Production/Stable" From bd0fa37c090d54b3a3a385fb73b864d93ff6b8a6 Mon Sep 17 00:00:00 2001 From: ckaros Date: Sun, 7 Sep 2025 14:30:32 -0400 Subject: [PATCH 02/12] remove build-requirements and update test-requirements --- swmm-toolkit/build-requirements.txt | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 swmm-toolkit/build-requirements.txt diff --git a/swmm-toolkit/build-requirements.txt b/swmm-toolkit/build-requirements.txt deleted file mode 100644 index 8c6bacb6..00000000 --- a/swmm-toolkit/build-requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ - - - -setuptools -wheel -scikit-build -cmake -swig From f9036c4d4730f933b39cf0c91eced1cb44630b45 Mon Sep 17 00:00:00 2001 From: ckaros Date: Sun, 7 Sep 2025 14:31:26 -0400 Subject: [PATCH 03/12] consolidate swmm_toolkit wheels --- .github/workflows/build_wheel.yml | 36 ++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index d56d7e96..ae3cb3bd 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -19,16 +19,15 @@ jobs: defaults: run: working-directory: ./nrtest-swmm - steps: - name: Checkout repo - uses: actions/checkout@v5 - + uses: actions/checkout@v3 + with: + submodules: true - name: Install Python uses: actions/setup-python@v5 with: python-version: "3.10" - - name: Build wheel run: | pip install wheel @@ -39,7 +38,6 @@ jobs: with: name: nrtest-swmm-wheel path: nrtest-swmm/dist/*.whl - build_wheels: runs-on: ${{ matrix.os }} @@ -47,13 +45,11 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-13, macos-latest] - steps: - name: Checkout repo uses: actions/checkout@v5 with: submodules: true - - name: Build wheels uses: pypa/cibuildwheel@v3.1.4 with: @@ -62,10 +58,8 @@ jobs: MACOSX_DEPLOYMENT_TARGET: "11.0" CIBW_TEST_COMMAND: "pytest {package}/tests" CIBW_BEFORE_TEST: pip install -r {package}/test-requirements.txt - CIBW_ENVIRONMENT_MACOS: | MACOSX_DEPLOYMENT_TARGET=11.0 - # remove system swig (cmake bug doesn't respect python venv) # https://github.com/swig/swig/issues/2481#issuecomment-1949573105 CIBW_BEFORE_BUILD_LINUX: rm -f $(which swig) && rm -f $(which swig4.0) @@ -76,11 +70,33 @@ jobs: # Skip trying to test arm64 builds on Intel Macs CIBW_TEST_SKIP: "*-*linux_{aarch64,ppc64le,s390x} *-macosx_universal2:arm64" CIBW_BUILD_VERBOSITY: 1 - - uses: actions/upload-artifact@v4 with: name: wheelhouse_${{ matrix.os }} path: ./wheelhouse/*.whl + merge_wheels: + name: Consolidate all wheel artifacts + runs-on: ubuntu-latest + needs: + - build_wheels + steps: + - name: Download all wheel artifacts + uses: actions/download-artifact@v5 + with: + path: wheelhouse + pattern: wheelhouse* + merge-multiple: true + - name: List downloaded wheels + run: ls -l wheelhouse + - name: Create consolidated archive + run: | + cd wheelhouse + zip -r ../all_swmm_toolkit_wheels.zip . + - name: Upload consolidated archive + uses: actions/upload-artifact@v4 + with: + name: all_swmm_toolkit_wheels + path: all_swmm_toolkit_wheels.zip From 4b5057266afe71be19c5b7bdeae304f5435f5dfc Mon Sep 17 00:00:00 2001 From: ckaros Date: Sun, 7 Sep 2025 14:26:56 -0400 Subject: [PATCH 04/12] - bundle openmp libraries and license - control stable abi compile definition with env var --- swmm-toolkit/extern/openmp.LICENSE | 361 +++++++++++++++++++ swmm-toolkit/pyproject.toml | 27 +- swmm-toolkit/src/swmm/toolkit/CMakeLists.txt | 48 ++- 3 files changed, 420 insertions(+), 16 deletions(-) create mode 100644 swmm-toolkit/extern/openmp.LICENSE diff --git a/swmm-toolkit/extern/openmp.LICENSE b/swmm-toolkit/extern/openmp.LICENSE new file mode 100644 index 00000000..d4e28d64 --- /dev/null +++ b/swmm-toolkit/extern/openmp.LICENSE @@ -0,0 +1,361 @@ +============================================================================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + +============================================================================== +Software from third parties included in the LLVM Project: +============================================================================== +The LLVM Project contains third party software which is under different license +terms. All such code will be identified clearly using at least one of two +mechanisms: +1) It will be in a separate directory tree with its own `LICENSE.txt` or + `LICENSE` file at the top containing the specific license and restrictions + which apply to that software, or +2) It will contain specific license and restriction terms at the top of every + file. + +============================================================================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): +============================================================================== + +The software contained in this directory tree is dual licensed under both the +University of Illinois "BSD-Like" license and the MIT license. As a user of +this code you may choose to use it under either license. As a contributor, +you agree to allow your code to be used under both. The full text of the +relevant licenses is included below. + +In addition, a license agreement from the copyright/patent holders of the +software contained in this directory tree is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 1997-2019 Intel Corporation + +All rights reserved. + +Developed by: + OpenMP Runtime Team + Intel Corporation + http://www.openmprtl.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of Intel Corporation OpenMP Runtime Team nor the + names of its contributors may be used to endorse or promote products + derived from this Software without specific prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 1997-2019 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +============================================================================== + +Intel Corporation + +Software Grant License Agreement ("Agreement") + +Except for the license granted herein to you, Intel Corporation ("Intel") reserves +all right, title, and interest in and to the Software (defined below). + +Definition + +"Software" means the code and documentation as well as any original work of +authorship, including any modifications or additions to an existing work, that +is intentionally submitted by Intel to llvm.org (http://llvm.org) ("LLVM") for +inclusion in, or documentation of, any of the products owned or managed by LLVM +(the "Work"). For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to LLVM or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems that are +managed by, or on behalf of, LLVM for the purpose of discussing and improving +the Work, but excluding communication that is conspicuously marked otherwise. + +1. Grant of Copyright License. Subject to the terms and conditions of this + Agreement, Intel hereby grants to you and to recipients of the Software + distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable copyright license to reproduce, prepare derivative + works of, publicly display, publicly perform, sublicense, and distribute the + Software and such derivative works. + +2. Grant of Patent License. Subject to the terms and conditions of this + Agreement, Intel hereby grants you and to recipients of the Software + distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable (except as stated in this section) patent license + to make, have made, use, offer to sell, sell, import, and otherwise transfer + the Work, where such license applies only to those patent claims licensable + by Intel that are necessarily infringed by Intel's Software alone or by + combination of the Software with the Work to which such Software was + submitted. If any entity institutes patent litigation against Intel or any + other entity (including a cross-claim or counterclaim in a lawsuit) alleging + that Intel's Software, or the Work to which Intel has contributed constitutes + direct or contributory patent infringement, then any patent licenses granted + to that entity under this Agreement for the Software or Work shall terminate + as of the date such litigation is filed. + +Unless required by applicable law or agreed to in writing, the software is +provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied, including, without limitation, any warranties or +conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. + +============================================================================== \ No newline at end of file diff --git a/swmm-toolkit/pyproject.toml b/swmm-toolkit/pyproject.toml index 763db0f9..77e05abd 100644 --- a/swmm-toolkit/pyproject.toml +++ b/swmm-toolkit/pyproject.toml @@ -1,8 +1,5 @@ [build-system] -requires = [ - "swig", - "scikit-build-core>=0.4.3", -] +requires = ["swig", "scikit-build-core>=0.4.3"] build-backend = "scikit_build_core.build" [project] @@ -10,7 +7,8 @@ name = "swmm-toolkit" version = "0.15.5" description = "PySWMM SWMM Python Toolkit" readme = { file = "README.md", content-type = "text/markdown" } -license = { text = "CC0" } +license = "CC0-1.0 AND (MIT OR Apache-2.0)" +license-files = ["LICEN[CS]E*", "AUTHORS", "extern/openmp.LICENSE"] authors = [{ name = "See AUTHORS" }] maintainers = [{ email = "bemcdonnell@gmail.com" }] keywords = ["swmm5", "swmm", "stormwater", "hydraulics", "hydrology"] @@ -19,7 +17,6 @@ classifiers = [ "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Operating System :: MacOS", - "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -47,7 +44,23 @@ cmake.args = ["-GUnix Makefiles"] [tool.scikit-build.wheel] packages = ["src/swmm/toolkit"] py-api = "cp39" -exclude = ["**/*runswmm*", "**/*.exe", "**/*.cmake", "**/*.h", "**/*.lib", "**/*.i", "**/CMakeLists.txt","toolkit/*", "lib/*", "bin/*", "build-env/*"] +exclude = [ + "**/*runswmm*", + "**/*.exe", + "**/*.cmake", + "**/*.h", + "**/*.lib", + "**/*.i", + "**/CMakeLists.txt", + "toolkit/*", + "lib/*", + "bin/*", + "build-env/*", +] + +[[tool.scikit-build.overrides]] +if.env.NO_STABLE_ABI = true +wheel.py-api = "" [tool.scikit-build.sdist] exclude = ["build-env/*"] diff --git a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt index 71496f02..a6a688d2 100644 --- a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt +++ b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt @@ -15,13 +15,25 @@ # set(CMAKE_SWIG_FLAGS -py3) # Determine filename suffix for python extension -set(CMAKE_MESSAGE_LOG_LEVEL VERBOSE) if(WIN32) - set(PYTHON_SUFFIX ".pyd") + set(SOABI "") + set(LIB_EXT "pyd") else() - set(PYTHON_SUFFIX ".abi3.so") + message(STATUS "Python3_SOABI in block") + set(SOABI ".abi3") + set(LIB_EXT "so") endif() +# turn if stable ABI if NO_STABLE_ABI is 1 or true +set(PY_LIMITED_API_DEF "Py_LIMITED_API=0x03090000") +string(TOLOWER "$ENV{NO_STABLE_ABI}" _abi_val) +if(_abi_val STREQUAL "1" OR _abi_val STREQUAL "true") + set(PY_LIMITED_API_DEF "") + set(SOABI ".${Python3_SOABI}") +endif() + +set(PYTHON_SUFFIX "${SOABI}.${LIB_EXT}") + # Location of package at runtime on MacOS/Linux if(APPLE) set(LIB_ROOT "@loader_path") @@ -88,8 +100,7 @@ set_target_properties(output BUILD_WITH_INSTALL_RPATH FALSE INSTALL_RPATH ${LIB_ROOT} INSTALL_RPATH_USE_LINK_PATH TRUE - # Enable stable ABI for Python 3.9+ - COMPILE_DEFINITIONS "Py_LIMITED_API=0x03090000" + COMPILE_DEFINITIONS "${PY_LIMITED_API_DEF}" ) install( @@ -156,11 +167,9 @@ set_target_properties(solver BUILD_WITH_INSTALL_RPATH FALSE INSTALL_RPATH ${LIB_ROOT} INSTALL_RPATH_USE_LINK_PATH TRUE - # Enable stable ABI for Python 3.9+ - COMPILE_DEFINITIONS "Py_LIMITED_API=0x03090000" + COMPILE_DEFINITIONS "${PY_LIMITED_API_DEF}" ) - # Stages python module for package build install( FILES @@ -178,4 +187,25 @@ install( DESTINATION "${PYTHON_INSTALL_DIR}" COMPONENT python -) \ No newline at end of file +) + +# Copy libomp.dylib on macOS if using scikit-build-core +if(APPLE AND DEFINED SKBUILD_PLATLIB_DIR) + install( + FILES + "${SKBUILD_PLATLIB_DIR}/lib/libomp.dylib" + DESTINATION + "${PYTHON_INSTALL_DIR}" + COMPONENT python + OPTIONAL + ) +# Copy copy dlls from build dir to python install dir +elseif(WIN32 AND DEFINED SKBUILD_PLATLIB_DIR) + install( + DIRECTORY "${SKBUILD_PLATLIB_DIR}/bin/" + DESTINATION "${PYTHON_INSTALL_DIR}" + COMPONENT python + FILES_MATCHING PATTERN "*.dll" + ) +endif() + From cbf133ad5f8a070466d8cddccf8e8a8793464618 Mon Sep 17 00:00:00 2001 From: ckaros Date: Sun, 7 Sep 2025 15:11:06 -0400 Subject: [PATCH 05/12] fix rebase regressions --- .github/workflows/build_wheel.yml | 4 +--- swmm-toolkit/pyproject.toml | 4 ++-- swmm-toolkit/src/swmm/toolkit/CMakeLists.txt | 3 +-- swmm-toolkit/src/swmm/toolkit/__init__.py | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index ae3cb3bd..36eb9061 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -21,9 +21,7 @@ jobs: working-directory: ./nrtest-swmm steps: - name: Checkout repo - uses: actions/checkout@v3 - with: - submodules: true + uses: actions/checkout@v5 - name: Install Python uses: actions/setup-python@v5 with: diff --git a/swmm-toolkit/pyproject.toml b/swmm-toolkit/pyproject.toml index 77e05abd..47607f60 100644 --- a/swmm-toolkit/pyproject.toml +++ b/swmm-toolkit/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build" [project] name = "swmm-toolkit" -version = "0.15.5" +version = "0.16.0" description = "PySWMM SWMM Python Toolkit" readme = { file = "README.md", content-type = "text/markdown" } license = "CC0-1.0 AND (MIT OR Apache-2.0)" @@ -26,7 +26,7 @@ classifiers = [ "Development Status :: 5 - Production/Stable", ] requires-python = ">=3.9" -dependencies = ["aenum==3.1.11"] +dependencies = ["aenum>=3.1.11"] urls = { Homepage = "https://github.com/pyswmm/swmm-python" } [[tool.scikit-build.overrides]] diff --git a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt index a6a688d2..8b05bd17 100644 --- a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt +++ b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt @@ -19,12 +19,11 @@ if(WIN32) set(SOABI "") set(LIB_EXT "pyd") else() - message(STATUS "Python3_SOABI in block") set(SOABI ".abi3") set(LIB_EXT "so") endif() -# turn if stable ABI if NO_STABLE_ABI is 1 or true +# turn off stable ABI if NO_STABLE_ABI is 1 or true set(PY_LIMITED_API_DEF "Py_LIMITED_API=0x03090000") string(TOLOWER "$ENV{NO_STABLE_ABI}" _abi_val) if(_abi_val STREQUAL "1" OR _abi_val STREQUAL "true") diff --git a/swmm-toolkit/src/swmm/toolkit/__init__.py b/swmm-toolkit/src/swmm/toolkit/__init__.py index ccab9cf0..f2e7f5dd 100644 --- a/swmm-toolkit/src/swmm/toolkit/__init__.py +++ b/swmm-toolkit/src/swmm/toolkit/__init__.py @@ -22,5 +22,5 @@ __date__ = "September 4, 2025" __maintainer__ = "Michael Tryby" -__email__ = "tryby.michael@epa.gov" +__email__ = "michael.tryby@gmail.com" __status__ = "Production/Stable" From 3629ced9a12e3741682a64ae4a90d3ab192823bd Mon Sep 17 00:00:00 2001 From: ckaros Date: Sun, 7 Sep 2025 15:24:10 -0400 Subject: [PATCH 06/12] don't double zip wheels --- .github/workflows/build_wheel.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 36eb9061..cfbc2fd3 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -85,16 +85,10 @@ jobs: path: wheelhouse pattern: wheelhouse* merge-multiple: true - - name: List downloaded wheels - run: ls -l wheelhouse - - name: Create consolidated archive - run: | - cd wheelhouse - zip -r ../all_swmm_toolkit_wheels.zip . - name: Upload consolidated archive uses: actions/upload-artifact@v4 with: name: all_swmm_toolkit_wheels - path: all_swmm_toolkit_wheels.zip + path: ./wheelhouse/*.whl From 4ecf6bfa4f2697f026d847ac17026bfb7c04e966 Mon Sep 17 00:00:00 2001 From: ckaros Date: Sun, 7 Sep 2025 22:00:04 -0400 Subject: [PATCH 07/12] include sdist in swmm-toolkit package --- .github/workflows/build_wheel.yml | 39 ++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index cfbc2fd3..904938b0 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -37,6 +37,29 @@ jobs: name: nrtest-swmm-wheel path: nrtest-swmm/dist/*.whl + build_sdist: + name: Build source distribution + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./swmm-toolkit + steps: + - name: Checkout repo + uses: actions/checkout@v5 + - name: Install Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Build sdist + run: | + pip install build + python -m build --sdist --outdir ./dist + - name: Upload sdist artifact + uses: actions/upload-artifact@v4 + with: + name: swmm-toolkit-sdist + path: swmm-toolkit/dist/*.tar.gz + build_wheels: runs-on: ${{ matrix.os }} strategy: @@ -64,13 +87,10 @@ jobs: # skip 3.8 and any free threaded variants CIBW_SKIP: cp38-* cp3??t-* CIBW_ARCHS: native - # Will avoid testing on emulated architectures - # Skip trying to test arm64 builds on Intel Macs - CIBW_TEST_SKIP: "*-*linux_{aarch64,ppc64le,s390x} *-macosx_universal2:arm64" CIBW_BUILD_VERBOSITY: 1 - uses: actions/upload-artifact@v4 with: - name: wheelhouse_${{ matrix.os }} + name: swmm-toolkit-bdist-${{ matrix.os }} path: ./wheelhouse/*.whl merge_wheels: @@ -79,16 +99,17 @@ jobs: needs: - build_wheels steps: - - name: Download all wheel artifacts + - name: Download all distribution artifacts uses: actions/download-artifact@v5 with: - path: wheelhouse - pattern: wheelhouse* + path: dist + pattern: swmm-toolkit-*dist* merge-multiple: true + - name: Upload consolidated archive uses: actions/upload-artifact@v4 with: - name: all_swmm_toolkit_wheels - path: ./wheelhouse/*.whl + name: swmm_toolkit_dist + path: ./dist/* From 105cac3ab0fab7d5cc354a1bc998b14cf32a4dbb Mon Sep 17 00:00:00 2001 From: ckaros Date: Mon, 8 Sep 2025 10:52:07 -0400 Subject: [PATCH 08/12] add build from source notes to readme and minor bug fix to build_wheel workflow --- .github/workflows/build_wheel.yml | 1 + swmm-toolkit/README.md | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 904938b0..fbe483ac 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -98,6 +98,7 @@ jobs: runs-on: ubuntu-latest needs: - build_wheels + - build_sdist steps: - name: Download all distribution artifacts uses: actions/download-artifact@v5 diff --git a/swmm-toolkit/README.md b/swmm-toolkit/README.md index 3a4ce0ed..12445223 100644 --- a/swmm-toolkit/README.md +++ b/swmm-toolkit/README.md @@ -16,7 +16,7 @@ ## Community -[![Discord](https://img.shields.io/badge/Discord-Join%20Chat-7289da?logo=discord&logoColor=white)](https://discord.com/channels/1412143058463756421/1412144907312955532) +[![Discord](https://img.shields.io/badge/Discord-Join%20Chat-7289da?logo=discord&logoColor=white)](https://discord.gg/U8wqxgjt9C) Join the discussion! We will do everything we can to help you! @@ -37,4 +37,23 @@ Run a SWMM simulation. from swmm.toolkit import solver solver.run('input_file.inp', 'report_file.rpt', 'output_file.out') + ``` + +## Build From Source + +> [!NOTE] +> Since version version 0.16.1, swmm-toolkit by default has been built and published +> using the [python stable ABI](https://docs.python.org/3/c-api/stable.html#stable-abi) for +> python 3.9 onward. Using the stable ABI introduces very minor performance reduction while +> substantially simplifying our release process and compatibility with future python versions. +> +> The commands below show how to build this package with and without using the python stable ABI. + +### Build with python stable ABI + +` python -m build .` + +### Build without python stable ABI + +` NO_STABLE_ABI=1 python -m build` \ No newline at end of file From 0b33d1ead2b3072a23769e43654ccb650545c562 Mon Sep 17 00:00:00 2001 From: karosc Date: Tue, 18 Nov 2025 09:32:40 -0500 Subject: [PATCH 09/12] update swig and fix deprecation https://github.com/swig/swig/blob/5a46275a33398d6f05d196cf6e8334a570d359fd/CHANGES#L135-L136 --- swmm-toolkit/pyproject.toml | 2 +- swmm-toolkit/src/swmm/toolkit/output.i | 6 +++--- swmm-toolkit/src/swmm/toolkit/solver.i | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/swmm-toolkit/pyproject.toml b/swmm-toolkit/pyproject.toml index 47607f60..1917f3bb 100644 --- a/swmm-toolkit/pyproject.toml +++ b/swmm-toolkit/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["swig", "scikit-build-core>=0.4.3"] +requires = ["swig>=4.4.0", "scikit-build-core>=0.4.3"] build-backend = "scikit_build_core.build" [project] diff --git a/swmm-toolkit/src/swmm/toolkit/output.i b/swmm-toolkit/src/swmm/toolkit/output.i index 6b894353..1d43bbcd 100644 --- a/swmm-toolkit/src/swmm/toolkit/output.i +++ b/swmm-toolkit/src/swmm/toolkit/output.i @@ -124,19 +124,19 @@ and return a (possibly) different pointer */ /* INSERTS CUSTOM EXCEPTION HANDLING IN WRAPPER */ %exception SMO_init { - $function + $action } %exception SMO_close { - $function + $action } %exception { char *err_msg; SMO_clearError(arg1); - $function + $action if (SMO_checkError(arg1, &err_msg)) { PyErr_SetString(PyExc_Exception, err_msg); diff --git a/swmm-toolkit/src/swmm/toolkit/solver.i b/swmm-toolkit/src/swmm/toolkit/solver.i index 03090212..d9ce6cf2 100644 --- a/swmm-toolkit/src/swmm/toolkit/solver.i +++ b/swmm-toolkit/src/swmm/toolkit/solver.i @@ -190,23 +190,23 @@ /* INSERTS CUSTOM EXCEPTION HANDLING IN WRAPPER */ %exception swmm_getSemVersion { - $function + $action } %exception swmm_getBuildId { - $function + $action } %exception swmm_getVersion { - $function + $action } /* INSERTS CUSTOM EXCEPTION HANDLING IN WRAPPER */ %exception { - $function + $action if (result > 0) { char* errorMsg = NULL; int errorCode = 0; From 89b1b4a0e7892e4ea5c7b5187c66d9f6d4213dc0 Mon Sep 17 00:00:00 2001 From: karosc Date: Tue, 18 Nov 2025 09:52:33 -0500 Subject: [PATCH 10/12] setup trusted publishing to pypi --- .github/workflows/build_wheel.yml | 44 ++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index fbe483ac..8ce2b976 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -28,9 +28,9 @@ jobs: python-version: "3.10" - name: Build wheel run: | - pip install wheel - python setup.py bdist_wheel - + pip install wheel + python setup.py bdist_wheel + - name: Upload wheel artifact uses: actions/upload-artifact@v4 with: @@ -52,8 +52,8 @@ jobs: python-version: "3.12" - name: Build sdist run: | - pip install build - python -m build --sdist --outdir ./dist + pip install build + python -m build --sdist --outdir ./dist - name: Upload sdist artifact uses: actions/upload-artifact@v4 with: @@ -65,12 +65,19 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-13, macos-latest] + os: + [ + ubuntu-latest, + ubuntu-24.04-arm, + windows-latest, + macos-13, + macos-latest, + ] steps: - name: Checkout repo uses: actions/checkout@v5 with: - submodules: true + submodules: true - name: Build wheels uses: pypa/cibuildwheel@v3.1.4 with: @@ -106,11 +113,30 @@ jobs: path: dist pattern: swmm-toolkit-*dist* merge-multiple: true - + - name: Upload consolidated archive uses: actions/upload-artifact@v4 with: name: swmm_toolkit_dist path: ./dist/* - + publish_toolkit: + name: Publish Python 🐍 distribution 📦 to PyPI + needs: + - merge_wheels + # only publish to PyPI on tag pushes + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/swmm-toolkit + permissions: + id-token: write + steps: + - name: Download all the dists + uses: actions/download-artifact@v5 + with: + name: swmm_toolkit_dist + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 From a5421af04e53b5229754926cbfc8b54778d72e24 Mon Sep 17 00:00:00 2001 From: karosc Date: Tue, 18 Nov 2025 10:03:28 -0500 Subject: [PATCH 11/12] set release version --- swmm-toolkit/CMakeLists.txt | 19 +++++++++---------- swmm-toolkit/pyproject.toml | 2 +- swmm-toolkit/src/swmm/toolkit/__init__.py | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/swmm-toolkit/CMakeLists.txt b/swmm-toolkit/CMakeLists.txt index 4f9df55b..7b35d564 100644 --- a/swmm-toolkit/CMakeLists.txt +++ b/swmm-toolkit/CMakeLists.txt @@ -4,31 +4,31 @@ # Created: Feb 6, 2020 # Modified Sep 2, 2025 # -# Author: See AUTHORS +# Author: See AUTHORS # -################################################################################ -################## CMAKELISTS FOR SWMM-TOOLKIT PROJECT ################### -################################################################################ +# ############################################################################### +# ################# CMAKELISTS FOR SWMM-TOOLKIT PROJECT ################### +# ############################################################################### -cmake_minimum_required (VERSION 4.0.2) +cmake_minimum_required(VERSION 4.0.2) project(swmm-toolkit VERSION - 0.15.5 + 0.16.1 ) - # Trick here is to perform build in a python virtual environment set(Python_FIND_VIRTUALENV FIRST) -#set(CMAKE_FIND_DEBUG_MODE TRUE) + +# set(CMAKE_FIND_DEBUG_MODE TRUE) if(NOT MSVC) find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module) else() find_package(Python3 REQUIRED COMPONENTS Interpreter Development) endif() -#set(CMAKE_FIND_DEBUG_MODE FALSE) +# set(CMAKE_FIND_DEBUG_MODE FALSE) # SWIG is a build requirement so needs to be installed first find_package(SWIG REQUIRED) @@ -36,7 +36,6 @@ cmake_policy(SET CMP0078 NEW) cmake_policy(SET CMP0086 NEW) include(${SWIG_USE_FILE}) - # Add project subdirectories add_subdirectory(swmm-solver) diff --git a/swmm-toolkit/pyproject.toml b/swmm-toolkit/pyproject.toml index 1917f3bb..f9e6c990 100644 --- a/swmm-toolkit/pyproject.toml +++ b/swmm-toolkit/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build" [project] name = "swmm-toolkit" -version = "0.16.0" +version = "0.16.1" description = "PySWMM SWMM Python Toolkit" readme = { file = "README.md", content-type = "text/markdown" } license = "CC0-1.0 AND (MIT OR Apache-2.0)" diff --git a/swmm-toolkit/src/swmm/toolkit/__init__.py b/swmm-toolkit/src/swmm/toolkit/__init__.py index f2e7f5dd..23eba132 100644 --- a/swmm-toolkit/src/swmm/toolkit/__init__.py +++ b/swmm-toolkit/src/swmm/toolkit/__init__.py @@ -18,7 +18,7 @@ __credits__ = "Colleen Barr" __license__ = "CC0 1.0 Universal" -__version__ = "0.16.0" +__version__ = "0.16.1" __date__ = "September 4, 2025" __maintainer__ = "Michael Tryby" From 283f40ea4987de5d8f9dda4898f270e6cc94db6d Mon Sep 17 00:00:00 2001 From: karosc Date: Tue, 18 Nov 2025 10:08:03 -0500 Subject: [PATCH 12/12] update deprecated action runners --- .github/workflows/build_wheel.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 8ce2b976..def381cc 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -67,11 +67,11 @@ jobs: matrix: os: [ - ubuntu-latest, + ubuntu-24.04, ubuntu-24.04-arm, - windows-latest, - macos-13, - macos-latest, + windows-2025, + macos-15-intel, + macos-15, ] steps: - name: Checkout repo