diff --git a/.github/actions/build-py/action.yml b/.github/actions/build-py/action.yml index 757f9f58a0..cec6a7b367 100644 --- a/.github/actions/build-py/action.yml +++ b/.github/actions/build-py/action.yml @@ -6,24 +6,38 @@ inputs: required: true runs: using: "composite" - steps: + steps: + - name: Configure Git safe directory + shell: bash + run: git config --global --add safe.directory /__w/memilio/memilio - name: Install dependencies shell: bash run: yum install ninja-build cmake git -qy - name: Make artifact dir shell: bash run: | - cd pycode/memilio-${{ inputs.package }}/ + if [ "${{ inputs.package }}" != "simulation" ]; then + cd pycode/memilio-${{ inputs.package }}/ + # else stay in root directory + fi mkdir wheelhouse - name: Build Python Wheels shell: bash run: | - cd pycode/memilio-${{ inputs.package }}/ + if [ "${{ inputs.package }}" != "simulation" ]; then + cd pycode/memilio-${{ inputs.package }}/ + # else stay in root directory + fi /opt/python/cp38-cp38/bin/python -m pip install --upgrade pip setuptools wheel - /opt/python/cp38-cp38/bin/python -m pip install scikit-build scikit-build-core - /opt/python/cp38-cp38/bin/python -m build --no-isolation --wheel /opt/python/cp312-cp312/bin/python -m pip install --upgrade pip setuptools wheel + /opt/python/cp38-cp38/bin/python -m pip install scikit-build scikit-build-core /opt/python/cp312-cp312/bin/python -m pip install scikit-build scikit-build-core + # Install setuptools-scm only for memilio-simulation + if [ "${{ inputs.package }}" == "simulation" ]; then + /opt/python/cp38-cp38/bin/python -m pip install setuptools-scm + /opt/python/cp312-cp312/bin/python -m pip install setuptools-scm + fi + /opt/python/cp38-cp38/bin/python -m build --no-isolation --wheel /opt/python/cp312-cp312/bin/python -m build --no-isolation --wheel # Exclude memilio-generation, because its a pure python package, cmake is only used in the build process to retrieve data from cpp if [[ -f "CMakeLists.txt" ]] && [ "${{ inputs.package }}" != "generation" ]; then @@ -33,7 +47,11 @@ runs: # no auditwheel necessary for pure python packages, so only copy the wheels to the same output directory cp dist/*.whl wheelhouse fi - cp -r wheelhouse .. + if [ "${{ inputs.package }}" != "simulation" ]; then + cp -r wheelhouse .. + else + cp -r wheelhouse pycode + fi - name: Upload Python Wheels uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml new file mode 100644 index 0000000000..57a2a3a782 --- /dev/null +++ b/.github/workflows/pypi.yml @@ -0,0 +1,62 @@ +name: PyPI + +on: + release: + types: + - published + +jobs: + + build_wheels: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pypa/cibuildwheel@v3.4.1 + + - uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.os }} + path: ./wheelhouse/*.whl + + build_sdist: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - run: pipx run build --sdist + + - uses: actions/upload-artifact@v4 + with: + name: cibw-sdist + path: dist/*.tar.gz + + upload_pypi: + needs: [build_wheels, build_sdist] + runs-on: ubuntu-latest + environment: pypi + permissions: + id-token: write + + steps: + - uses: actions/download-artifact@v4 + with: + # unpacks all CIBW artifacts into dist/ + pattern: cibw-* + path: dist + merge-multiple: true + + - uses: pypa/gh-action-pypi-publish@release/v1 + with: + skip-existing: true + # To test uploads to TestPyPI, uncomment the following: + # repository-url: https://test.pypi.org/legacy/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..0a29cfcdba --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.14) +project(memilio-simulation) + +set(CMAKE_CXX_STANDARD "20") +set(CMAKE_CXX_STANDARD_REQUIRED "20") + +# add in C++ library +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/cpp ${CMAKE_CURRENT_BINARY_DIR}/cpp EXCLUDE_FROM_ALL) + +add_subdirectory(pycode/memilio-simulation) \ No newline at end of file diff --git a/README.md b/README.md index 512500cf7d..e99726ab43 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MEmilio - a high performance Modular EpideMIcs simuLatIOn software # -![memilio_logo](docs/memilio-small.png) +![memilio_logo](https://github.com/SciCompMod/memilio/blob/main/docs/memilio-small.png?raw=true) [![CI](https://github.com/SciCompMod/memilio/actions/workflows/main.yml/badge.svg)](https://github.com/SciCompMod/memilio/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/SciCompMod/memilio/branch/main/graph/badge.svg?token=DVQXIQJHBM)](https://codecov.io/gh/SciCompMod/memilio) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 1031123289..a76f4865f2 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -300,39 +300,70 @@ Option A: Installing the Python packages (Recommended for nonexperienced users o You can run simulations, download data, or create plots, by only installing our Python packages. +Installing ``memilio-simulation`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The simulation package ``memilio-simulation`` provides two installation options depending on your use case: + +**Option A.1: Install from PyPI (Recommended - no C++ compiler required)** + +If you just want to run simulations with the latest released version, install the pre-built wheel directly from PyPI: + +.. code-block:: console + + pip install memilio-simulation + +This requires no C++ compiler or CMake. Pre-built wheels are provided for Linux and Windows on Python 3.8 to 3.13. + +**Option A.2: Install from source (for the latest development version)** + +If you need the latest (unreleased) code, or want to contribute to the package, you need to build from source. +This requires a **C++20 compiler** (e.g. GCC or Clang), **CMake** (>= 3.18), and **Ninja**. + +.. code-block:: console + + pip install -e .[dev] + +This command must be run from the **root of the MEmilio repository** (the directory containing the top-level ``pyproject.toml``). +This is necessary because the C++ build requires access to the ``cpp/`` directory. +Note that this only installs ``memilio-simulation`` and not any other Python packages. The root-level ``pyproject.toml`` belongs exclusively to ``memilio-simulation``. + +.. warning:: + C++ code changes always require re-running ``pip install -e .[dev]`` to recompile. + +Installing other Python packages +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 1. Navigate to the directory containing our Python code: .. code-block:: console cd pycode -2. To install the simulation package ``memilio-simulation``, from here you can do: +2. To install the ``memilio-epidata`` package for data downloading and handling: .. code-block:: console - cd memilio-simulation + cd memilio-epidata pip install -e . -3. For afterwards installing the ``memilio-epidata`` package for data downloading and handling, run: +3. To install the ``memilio-surrogatemodel`` package for surrogate models: .. code-block:: console cd .. # Go back to the pycode directory - cd memilio-epidata + cd memilio-surrogatemodel pip install -e . .. tip:: For Contributors: Installing development packages The ``-e`` flag installs the package in a mode, which links the installation to your local source code folder. - - If you plan to contribute to MEmilio, you can also install all the necessary development dependencies by adding ``[dev]`` to the command: + If you plan to contribute to any package, install all development dependencies by adding ``[dev]``: .. code-block:: console pip install -e .[dev] - For regular use, the simple ``pip install -e .`` is sufficient. - To install other packages, see the items below *Python Interface* in the menu on the left hand side. Option B: Building the C++ core (Advanced) diff --git a/docs/source/python/m-simulation.rst b/docs/source/python/m-simulation.rst index fc1d97abe2..f47a6e0045 100644 --- a/docs/source/python/m-simulation.rst +++ b/docs/source/python/m-simulation.rst @@ -5,12 +5,49 @@ MEmilio Simulation is a Python interface to the MEmilio C++ library. Using pytho The package is contained inside the folder `pycode/memilio-simulation `_. +Installation +------------ + +The ``memilio-simulation`` package can be installed in two ways depending on your use case. + +**Option 1: Install from PyPI (Recommended - no C++ compiler required)** + +Pre-built wheels are provided for Linux and Windows on Python 3.8 to 3.13. + +.. code-block:: console + + pip install memilio-simulation + +This is the easiest way to get started. No C++ compiler or CMake is needed. + +**Option 2: Install from source (latest development version, or contributing)** + +If you need the latest unreleased code, or want to modify the bindings, build from source. + +Requirements: + +* A **C++20 compiler** +* **CMake** >= 3.18 +* **Ninja** build tool +* All :doc:`C++ library dependencies <../getting_started>` + +Install from the **root of the MEmilio repository** (the directory containing the top-level ``pyproject.toml``): + +.. code-block:: console + + pip install -e .[dev] + +This is necessary because the C++ build requires access to the ``cpp/`` directory. +Note that this only installs ``memilio-simulation`` and not any other Python packages.The ``-e`` flag links the installation to your local source code so Python changes are reflected immediately. +C++ changes require re-running this command to recompile. + Dependencies ------------ -Required Python packages: +Required Python packages (installed automatically): -* scikit-build +* numpy >= 1.22 (not 1.25.*) +* pandas >= 2.0.0 For a successful build, the development libraries for Python need to be installed, i.e. python3.x-dev. Additionally, as this package builds upon the MEmilio C++ library, diff --git a/pycode/memilio-simulation/CMakeLists.txt b/pycode/memilio-simulation/CMakeLists.txt index e7bc5a8f20..668da85628 100644 --- a/pycode/memilio-simulation/CMakeLists.txt +++ b/pycode/memilio-simulation/CMakeLists.txt @@ -1,9 +1,3 @@ -cmake_minimum_required(VERSION 3.14) -project(memilio-python) - -set(CMAKE_CXX_STANDARD "20") -set(CMAKE_CXX_STANDARD_REQUIRED "20") - option(MEMILIO_USE_BUNDLED_PYBIND11 "Use pybind11 bundled with this library." ON) mark_as_advanced(MEMILIO_USE_BUNDLED_PYBIND11) @@ -48,9 +42,6 @@ else() find_package(pybind11 REQUIRED) endif() -# add in C++ library -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../cpp ${CMAKE_CURRENT_BINARY_DIR}/cpp EXCLUDE_FROM_ALL) - # a list of all "LINKED_LIBRARIES" that are given to add_pymio_module. will contain duplicates # used for wheel installation set(PYMIO_MEMILIO_LIBS_LIST) diff --git a/pycode/memilio-simulation/README.md b/pycode/memilio-simulation/README.md index 76f0ab82e7..d521a36e04 100644 --- a/pycode/memilio-simulation/README.md +++ b/pycode/memilio-simulation/README.md @@ -4,17 +4,34 @@ This package contains Python bindings for the MEmilio C++ library. It enables se ## Installation -This project is configured via ``pyproject.toml`` and is built with [scikit-build-core](https://scikit-build-core.readthedocs.io). CMake and Ninja must be available on the system. The package uses the [Pybind11 C++ library](https://pybind11.readthedocs.io) to create the bindings. +### Option 1: Install from PyPI (Recommended) -To install the package, use the command (from the directory containing ``pyproject.toml``) +Pre-built wheels are provided for Linux and Windows on Python 3.8 to 3.13. ```bash -pip install . +pip install memilio-simulation ``` -This builds the C++ library and C++ Python extension module and copies everything required to your site-packages. +### Option 2: Install from source (latest code or development) -All the requirements of the [C++ library](../../cpp/README.md) must be met in order to build and use the python bindings. A virtual environment is recommended. +Use this option if you need the latest unreleased code, or want to modify the C++ bindings. + +This project is configured via `pyproject.toml`. The following tools must be available on the system: + +- A **C++20 compiler** +- **CMake** >= 3.18 +- **Ninja** +- All [C++ library dependencies](../../cpp/README.md) + +A virtual environment is recommended. Install from the **root of the MEmilio repository** (the directory containing the top-level `pyproject.toml`): + +```bash +pip install -e .[dev] +``` + +This is necessary because the C++ build requires access to the `cpp/` directory. Note that this only installs `memilio-simulation` and not any other Python packages. + +**Note:** The `-e` flag links the installation to your local source code. Python changes take effect immediately, but C++ changes require re-running this command to recompile. CMake is executed internally by scikit-build-core. All the options provided by the CMake configuration of the C++ library are available when building the Python extension as well. Additionally, the CMake configuration for the bindings provide the following CMake options: @@ -30,7 +47,7 @@ Alternatively, edit the `CMakeCache.txt` in the directory created by scikit-buil ## Development -For developement of the cpp bindings use +For developement of the cpp bindings use the following command from the root of this repository (i.e. the directory containing ``pyproject.toml``) ```bash pip install -e .[dev] diff --git a/pycode/memilio-simulation/pyproject.toml b/pycode/memilio-simulation/pyproject.toml deleted file mode 100644 index d7bc24b90f..0000000000 --- a/pycode/memilio-simulation/pyproject.toml +++ /dev/null @@ -1,39 +0,0 @@ -[build-system] -requires = [ - "scikit-build-core>=0.9.0", - "setuptools>=68", - "wheel" -] -build-backend = "scikit_build_core.build" - -[project] -name = "memilio-simulation" -version = "1.0.0" -description = "Part of MEmilio project, python bindings to the C++ libraries that contain the models and simulations." -readme = "README.md" -requires-python = ">=3.8" -license = { text = "Apache-2.0" } -authors = [{ name = "MEmilio Team" }] -maintainers = [ - { email = "martin.kuehn@dlr.de" } -] -dependencies = [ - # smaller numpy versions cause a security issue, 1.25 does not work together with pyfakefs - "numpy>=1.22,!=1.25.*", - # smaller pandas versions contain a bug that sometimes prevents reading - "pandas>=2.0.0" -] - -[project.optional-dependencies] -dev = [] - -[project.urls] -Homepage = "https://github.com/SciCompMod/memilio" -Team = "https://memilio.readthedocs.io/en/latest/team.html" - -[tool.scikit-build] -cmake.version = ">=3.13" -cmake.args = ["-DMEMILIO_BUILD_SHARED_LIBS:BOOL=ON"] -wheel.packages = ["memilio"] -wheel.install-dir = "memilio/simulation" -build-dir = "../build/memilio-simulation" diff --git a/pyproject.toml b/pyproject.toml index 2f12cc6b19..15fa1202dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,67 @@ +[project] +# Note that this file is only installing the memilio-simulation package. For installing the other Python packages, +# please go to the respective folder pycode/memilio-* and install from there. +name = "memilio-simulation" +dynamic = ["version"] +description = "Part of MEmilio project, Python bindings to the C++ libraries that contain the models and simulations." +readme = "README.md" +requires-python = ">=3.8" +license = "Apache-2.0" +authors = [{ name = "MEmilio Team" }] +maintainers = [ + { email = "martin.kuehn@dlr.de" } +] +dependencies = [ + # smaller numpy versions cause a security issue, 1.25 does not work together with pyfakefs + "numpy>=1.22,!=1.25.*", + # smaller pandas versions contain a bug that sometimes prevents reading + "pandas>=2.0.0" +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "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", + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows" +] + +[project.optional-dependencies] +dev = [] + +[project.urls] +Homepage = "https://github.com/SciCompMod/memilio" +Team = "https://memilio.readthedocs.io/en/latest/team.html" + +[build-system] +requires = [ + "scikit-build-core>=0.9.0", + "setuptools>=68", + "setuptools-scm>=8", + "wheel" +] +build-backend = "scikit_build_core.build" + +[tool.scikit-build] +cmake.version = ">=3.13" +cmake.args = ["-DMEMILIO_BUILD_SHARED_LIBS:BOOL=ON"] +wheel.packages = ["pycode/memilio-simulation/memilio"] +wheel.install-dir = "memilio/simulation" +build-dir = "pycode/build/memilio-simulation" +metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" + +[tool.setuptools_scm] +local_scheme = "no-local-version" + +[tool.cibuildwheel] +# Disable some wheels +skip = ["pp*", "*musllinux*", "*-win32", "cp314*"] + [tool.autopep8] max-line-length = 79