diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 92fa2f8c..def381cc 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -19,42 +19,65 @@ jobs: defaults: run: working-directory: ./nrtest-swmm - steps: - name: Checkout repo uses: actions/checkout@v5 - - name: Install Python uses: actions/setup-python@v5 with: - python-version: '3.10' - + 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: 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: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - pyver: [cp39, cp310, cp311, cp312, cp313] - + os: + [ + ubuntu-24.04, + ubuntu-24.04-arm, + windows-2025, + macos-15-intel, + macos-15, + ] steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: - submodules: true - + submodules: true - name: Build wheels uses: pypa/cibuildwheel@v3.1.4 with: @@ -63,65 +86,57 @@ 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* - # 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" + # skip 3.8 and any free threaded variants + CIBW_SKIP: cp38-* cp3??t-* + CIBW_ARCHS: native CIBW_BUILD_VERBOSITY: 1 - - uses: actions/upload-artifact@v4 with: - name: wheels-${{ matrix.os }}-${{ matrix.pyver }} + name: swmm-toolkit-bdist-${{ matrix.os }} path: ./wheelhouse/*.whl - build_cross_wheels: + merge_wheels: + name: Consolidate all wheel artifacts runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - pyver: [cp39, cp310, cp311, cp312, cp313] - + needs: + - build_wheels + - build_sdist steps: - - name: Checkout repo - uses: actions/checkout@v5 + - name: Download all distribution artifacts + uses: actions/download-artifact@v5 with: - submodules: true + path: dist + pattern: swmm-toolkit-*dist* + merge-multiple: true - - name: Set up QEMU - if: runner.os == 'Linux' - uses: docker/setup-qemu-action@v2 + - name: Upload consolidated archive + uses: actions/upload-artifact@v4 with: - platforms: all + name: swmm_toolkit_dist + path: ./dist/* - - 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 + 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: wheels-linux-aarch64-${{ matrix.pyver }} - path: ./wheelhouse/*.whl + name: swmm_toolkit_dist + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 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..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 ${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) +# 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/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 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 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 538bcb3e..f9e6c990 100644 --- a/swmm-toolkit/pyproject.toml +++ b/swmm-toolkit/pyproject.toml @@ -1,10 +1,66 @@ [build-system] -requires = [ - "wheel>=0.38.1", - "setuptools>=42", - "scikit-build>=0.13", - "cmake>=3.21", - "swig", - "ninja==1.11.1 ; sys_platform == 'darwin'", +requires = ["swig>=4.4.0", "scikit-build-core>=0.4.3"] +build-backend = "scikit_build_core.build" + +[project] +name = "swmm-toolkit" +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)" +license-files = ["LICEN[CS]E*", "AUTHORS", "extern/openmp.LICENSE"] +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", + "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", ] -build-backend = "setuptools.build_meta" +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.overrides]] +if.env.NO_STABLE_ABI = true +wheel.py-api = "" + +[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..8b05bd17 100644 --- a/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt +++ b/swmm-toolkit/src/swmm/toolkit/CMakeLists.txt @@ -16,12 +16,22 @@ # Determine filename suffix for python extension if(WIN32) + set(SOABI "") set(LIB_EXT "pyd") else() + set(SOABI ".abi3") set(LIB_EXT "so") endif() -set(PYTHON_SUFFIX ".${Python3_SOABI}.${LIB_EXT}") +# 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") + 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) @@ -30,11 +40,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 +87,6 @@ target_include_directories(output target_link_libraries(output PUBLIC - $<$>:Python3::Module> swmm-output ) @@ -78,8 +97,9 @@ 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 + COMPILE_DEFINITIONS "${PY_LIMITED_API_DEF}" ) install( @@ -89,14 +109,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 +154,6 @@ target_include_directories(solver target_link_libraries(solver PUBLIC - $<$>:Python3::Module> swmm5 ) @@ -142,23 +164,47 @@ 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 + COMPILE_DEFINITIONS "${PY_LIMITED_API_DEF}" ) - # Stages python module for package build 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 +) + +# 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() + diff --git a/swmm-toolkit/src/swmm/toolkit/__init__.py b/swmm-toolkit/src/swmm/toolkit/__init__.py index 7ac565cc..23eba132 100644 --- a/swmm-toolkit/src/swmm/toolkit/__init__.py +++ b/swmm-toolkit/src/swmm/toolkit/__init__.py @@ -18,27 +18,9 @@ __credits__ = "Colleen Barr" __license__ = "CC0 1.0 Universal" -__version__ = "0.16.0" +__version__ = "0.16.1" __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"] +__status__ = "Production/Stable" 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;