Skip to content

Commit

Permalink
Create package Ribasim API (#130)
Browse files Browse the repository at this point in the history
This PR creates the package similar to
https://github.com/MODFLOW-USGS/modflowapi

- This allows to expose functionality that doesn't fit into xmipy
- Allows us to override xmipy functionality (in our case
`get_constant_int` but ideally we would get rid of that mid-term)

The PR also moves shared config like `environment.yml` and `ruff.toml`
into the root of the repo
  • Loading branch information
Hofer-Julian authored Mar 23, 2023
1 parent a9c61b0 commit b8c71ff
Show file tree
Hide file tree
Showing 31 changed files with 145 additions and 60 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,10 @@ jobs:
python_version: ${{ matrix.python_version }}
cache-downloads: true
cache-env: true
environment-file: ./python/environment.yml
environment-file: ./environment.yml

- name: Install ribasim-python
working-directory: python
run: pip install -e .
run: pip install -e python/ribasim

- name: Set up Quarto
uses: quarto-dev/quarto-actions/setup@v2
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/python_lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ jobs:
python_version: ${{ matrix.python_version }}
cache-downloads: true
cache-env: true
environment-file: ./python/environment.yml
environment-file: ./environment.yml

- name: Run black
working-directory: python
run: black --check .
run: |
black --check python
# Include `--format=github` to enable automatic inline annotations.
- name: Run ruff
working-directory: python
run: ruff check --format=github .
run: |
ruff check --format=github python
8 changes: 3 additions & 5 deletions .github/workflows/python_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ jobs:
python_version: ${{ matrix.python_version }}
cache-downloads: true
cache-env: true
environment-file: ./python/environment.yml
environment-file: ./environment.yml

- name: Install ribasim
working-directory: python
run: pip install -e .
run: pip install -e python/ribasim

- name: Run tests
working-directory: python
run: pytest tests
run: pytest python/ribasim/tests
6 changes: 1 addition & 5 deletions .vscode/settings_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,5 @@
},
"python.formatting.provider": "black",
"python.linting.mypyEnabled": true,
"python.linting.enabled": true,
"ruff.args": [
"--config",
"python/pyproject.toml"
]
"python.linting.enabled": true
}
6 changes: 0 additions & 6 deletions docs/python/developer.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

## Creating (or updating) the environment

- Change your current working directory to `python`

```
cd python
```

- Create (or update) the environment by executing the following in your terminal:

```
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
16 changes: 0 additions & 16 deletions python/ribasim/__init__.py

This file was deleted.

7 changes: 1 addition & 6 deletions python/pyproject.toml → python/ribasim/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ readme = "README.md"
authors = [
{ name = "Huite Bootsma", email = "[email protected]" },
{ name = "Julian Hofer", email = "[email protected]" },
{ name = "Martijn Visser", email = "[email protected]" },
]
license = { text = "MIT" }
classifiers = [
Expand All @@ -32,7 +33,6 @@ dynamic = ["version"]

[project.optional-dependencies]
tests = ["pytest", "pytest-cov"]
lint = ["black", "ruff", "mypy"]

[tool.setuptools]
zip-safe = true
Expand All @@ -49,8 +49,3 @@ include = ["ribasim"]
[project.urls]
Documentation = "https://deltares.github.io/Ribasim"
Source = "https://github.com/Deltares/Ribasim"

[tool.ruff]
select = ["E", "F", "NPY", "PD", "C4", "I"]
ignore = ["E501", "PD901"]
fixable = ["I"]
27 changes: 27 additions & 0 deletions python/ribasim/ribasim/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
__version__ = "0.1.1"


from ribasim import utils
from ribasim.basin import Basin
from ribasim.edge import Edge
from ribasim.fractional_flow import FractionalFlow
from ribasim.level_control import LevelControl
from ribasim.linear_level_connection import LinearLevelConnection
from ribasim.model import Model, Solver
from ribasim.node import Node
from ribasim.pump import Pump
from ribasim.tabulated_rating_curve import TabulatedRatingCurve

__all__ = [
"utils",
"Basin",
"Edge",
"FractionalFlow",
"LevelControl",
"LinearLevelConnection",
"Model",
"Solver",
"Node",
"Pump",
"TabulatedRatingCurve",
]
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import pytest
import shapely.geometry as sg
from pydantic import ValidationError

from ribasim.edge import Edge


Expand Down
21 changes: 21 additions & 0 deletions python/ribasim_api/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Ribasim developers

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.
40 changes: 40 additions & 0 deletions python/ribasim_api/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

[project]
name = "ribasim_api"
description = "Python bindings for libribasim"
readme = "README.md"
authors = [
{ name = "Julian Hofer", email = "[email protected]" },
]
license = { text = "MIT" }
classifiers = [
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering :: Hydrology",
]
requires-python = ">=3.10"
dependencies = [
"xmipy"
]
dynamic = ["version"]

[project.optional-dependencies]
tests = ["pytest", "pytest-cov"]

[tool.setuptools]
zip-safe = true

[tool.setuptools.dynamic]
version = { attr = "ribasim_api.__version__" }

[tool.setuptools.packages.find]
include = ["ribasim_api"]

[tool.setuptools.package-data]
"ribasim" = ["py.typed"]

[project.urls]
Documentation = "https://deltares.github.io/Ribasim"
Source = "https://github.com/Deltares/Ribasim"
5 changes: 5 additions & 0 deletions python/ribasim_api/ribasim_api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
__version__ = "0.1.1"

from ribasim_api.ribasim_api import RibasimApi

__all__ = ["RibasimApi"]
29 changes: 29 additions & 0 deletions python/ribasim_api/ribasim_api/ribasim_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# %%
from ctypes import byref, c_int, create_string_buffer

from xmipy import XmiWrapper


class RibasimApi(XmiWrapper):
def get_constant_int(self, name: str) -> int:
match name:
case "BMI_LENVARTYPE":
return 51
case "BMI_LENGRIDTYPE":
return 17
case "BMI_LENVARADDRESS":
return 68
case "BMI_LENCOMPONENTNAME":
return 256
case "BMI_LENVERSION":
return 256
case "BMI_LENERRMESSAGE":
return 1025
raise ValueError(f"{name} does not map to an integer exposed by Ribasim")

def init_julia(self) -> None:
argument = create_string_buffer(0)
self.lib.init_julia(c_int(0), byref(argument))

def shutdown_julia(self) -> None:
self.lib.shutdown_julia(c_int(0))
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
from ctypes import byref, c_int, create_string_buffer
from pathlib import Path

import pytest
from xmipy import XmiWrapper
from ribasim_api import RibasimApi


@pytest.fixture(scope="session")
def libribasim_paths() -> tuple[Path, Path]:
test_dir = Path(__file__).parent.resolve()
lib_folder = test_dir.parents[1] / "create_binaries" / "libribasim" / "bin"
repo_root = Path(__file__).parents[2].resolve()
lib_folder = repo_root / "build" / "create_binaries" / "libribasim" / "bin"
lib_path = lib_folder / "libribasim"
return lib_path, lib_folder


@pytest.fixture(scope="session", autouse=True)
def load_julia(libribasim_paths) -> None:
lib_path, lib_folder = libribasim_paths
libribasim = XmiWrapper(lib_path, lib_folder)
argument = create_string_buffer(0)
libribasim.lib.init_julia(c_int(0), byref(argument))
libribasim = RibasimApi(lib_path, lib_folder)
libribasim.init_julia()


@pytest.fixture
def ribasim_basic(libribasim_paths, request) -> tuple[XmiWrapper, str]:
def ribasim_basic(libribasim_paths, request) -> tuple[RibasimApi, str]:
lib_path, lib_folder = libribasim_paths
libribasim = XmiWrapper(lib_path, lib_folder)
libribasim = RibasimApi(lib_path, lib_folder)

# If initialized, call finalize() at end of use
request.addfinalizer(libribasim.__del__)

repo_root = Path(__file__).parents[3].resolve()
repo_root = Path(__file__).parents[2].resolve()
config_file = str(repo_root / "data" / "basic" / "basic.toml")

return libribasim, config_file
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from xmipy import XmiWrapper


def test_initialize(ribasim_basic):
libribasim, config_file = ribasim_basic
libribasim.initialize(config_file)
Expand Down
3 changes: 3 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select = ["E", "F", "NPY", "PD", "C4", "I"]
ignore = ["E501", "PD901"]
fixable = ["I"]

0 comments on commit b8c71ff

Please sign in to comment.