Skip to content

Commit

Permalink
Merge pull request #71 from DHI/feature/linux_support
Browse files Browse the repository at this point in the history
Initial implementation of Linux support.
  • Loading branch information
gedaskir authored Dec 21, 2023
2 parents 38d133f + bc98fcb commit 09273b7
Show file tree
Hide file tree
Showing 16 changed files with 233 additions and 83 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/full_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ on:
jobs:
build:

runs-on: windows-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
os: [ubuntu-latest, windows-latest]
python-version: ["3.8", "3.12"]

steps:
- uses: actions/checkout@v3
Expand All @@ -26,7 +27,7 @@ jobs:
- name: Set up .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '5.0'
dotnet-version: '6.0.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
23 changes: 13 additions & 10 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ on:
jobs:
deploy:

runs-on: windows-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]

permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
Expand All @@ -26,24 +30,23 @@ jobs:
- name: Set up .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '5.0'
dotnet-version: '6.0.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
pip install setuptools build wheel twine
- name: Build
run: |
python setup.py sdist bdist_wheel
python -m build --wheel
# Doesn't run on Windows ☹️
# - name: Publish package distributions to PyPI
# uses: pypa/gh-action-pypi-publish@release/v1
- name: Build and publish

- name: Publish
env:
TWINE_USERNAME: '__token__'
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
twine upload dist/*.whl
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ mikeio1d/bin/*.dll
mikeio1d/bin/*.pfs
mikeio1d/bin/*.ubg
mikeio1d/bin/*.xml
mikeio1d/bin/*so.5

# Specific files
tests/testdata/NetworkRiver.mod.res1d
Expand Down
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

### Added

- Linux support.

### Fixed

### Changed

## 0.4.1 - 2023-12-14
## [0.4.1] - 2023-12-14

### Added

Expand All @@ -22,7 +24,7 @@

- Use MIKE 1D NuGet packages v22.0.3 and v22.0.4 for DHI.Mike1D.ResultDataAccess

## [0.4]
## [0.4] - 2023-09-14

### Added

Expand Down Expand Up @@ -85,6 +87,7 @@


[unreleased]: https://github.com/DHI/mikeio1d/compare/v0.4...HEAD
[0.4.1]: https://github.com/DHI/mikeio1d/releases/tag/v0.4.1
[0.4]: https://github.com/DHI/mikeio1d/releases/tag/v0.4
[0.3]: https://github.com/DHI/mikeio1d/releases/tag/v0.3
[0.2]: https://github.com/DHI/mikeio1d/releases/tag/v0.2
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Read res1d and xns11 files.
For other MIKE files (Dfs0, Dfs1, Dfs2, Dfsu,...) use the related package [MIKE IO](https://github.com/DHI/mikeio)

## Requirements
* Windows operating system
* Windows operating system (Support for Linux is experimental)
* Python x64 3.6, 3.7 or 3.8
* [VC++ redistributables](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads) (already installed if you have MIKE)

Expand All @@ -21,6 +21,10 @@ Or development version:
`pip install https://github.com/DHI/mikeio1d/archive/main.zip`


For MIKE IO 1D to work .NET runtime environment (version 3.1 and above) is needed. On Linux operating systems this is not available per default. For example, on Ubuntu distribution to get .NET 7.0 runtime call:

`sudo apt install dotnet-runtime-7.0`

## Where can I get help?

* New ideas and feature requests - [GitHub Discussions](http://github.com/DHI/mikeio1d/discussions)
Expand Down
10 changes: 5 additions & 5 deletions mikeio1d/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import clr
import sys
import os
from platform import architecture
import platform

from .mikepath import MikePath

Expand All @@ -21,13 +19,15 @@
# Dev branch marker is: 'X.Y.dev' or 'X.Y.devN' where N is an integer.
# 'X.Y.dev0' is the canonical version of 'X.Y.dev'
#
__version__ = "0.4.1"
__version__ = "0.5.dev0"

if "64" not in architecture()[0]:
if "64" not in platform.architecture()[0]:
raise Exception("This library has not been tested for a 32 bit system.")

MikePath.setup_mike_installation(sys.path)

import clr

clr.AddReference("System")
clr.AddReference("System.Runtime")
clr.AddReference("System.Runtime.InteropServices")
Expand Down
13 changes: 13 additions & 0 deletions mikeio1d/bin/DHI.Mike1D.Application.runtimeconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"runtimeOptions": {
"tfm": "netcoreapp3.1",
"rollForward": "LatestMajor",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "3.1.0"
},
"configProperties": {
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false
}
}
}
21 changes: 16 additions & 5 deletions mikeio1d/dotnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,25 @@

def to_dotnet_datetime(x):
"""Convert from python datetime to .NET System.DateTime"""
milliseconds = x.microsecond // 1000
return System.DateTime(x.year, x.month, x.day, x.hour, x.minute, x.second, milliseconds)
dotnet_datetime = System.DateTime(x.year, x.month, x.day, x.hour, x.minute, x.second)
# Get .NET ticks microseconds
ticks = x.microsecond * 10
dotnet_datetime = dotnet_datetime.AddTicks(ticks)
return dotnet_datetime


def from_dotnet_datetime(x):
def from_dotnet_datetime(x, round_to_milliseconds=True):
"""Convert from .NET System.DateTime to python datetime"""
microseconds = x.Millisecond * 1000
return datetime.datetime(x.Year, x.Month, x.Day, x.Hour, x.Minute, x.Second, microseconds)
# Get microseconds from .NET ticks
microseconds = x.Ticks % 10**7 // 10
time = datetime.datetime(x.Year, x.Month, x.Day, x.Hour, x.Minute, x.Second, microseconds)

# Round to milliseconds if requested
if round_to_milliseconds:
microseconds_rounded = round(time.microsecond, -3)
time = time.replace(microsecond=microseconds_rounded)

return time


def asNumpyArray(x):
Expand Down
51 changes: 37 additions & 14 deletions mikeio1d/mikepath.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import os
import platform
import pythonnet


class MikePath:
Expand All @@ -19,6 +21,8 @@ class MikePath:
Actual path for MIKE binaries, which is either mikeio1d_bin_path or mike_install_path/bin/x64.
"""

is_linux = platform.system() == "Linux"

mikeio1d_bin_path = os.path.join(os.path.dirname(__file__), "bin")

mike_install_path = os.environ.get("MIKE_INSTALL_PATH", None)
Expand All @@ -45,21 +49,40 @@ def setup_mike_installation(syspath):
syspath: list of str
List of strings defining PATH variable.
"""
mike_bin_path = MikePath.mike_bin_path
mikeio1d_bin_path = MikePath.mikeio1d_bin_path
mike_install_path = MikePath.mike_install_path
syspath.append(MikePath.mike_bin_path)

if MikePath.is_linux:
MikePath.setup_mike_installation_linux()

syspath.append(mike_bin_path)
if mikeio1d_bin_path != mike_bin_path:
syspath.append(mikeio1d_bin_path)
if MikePath.mikeio1d_bin_path != MikePath.mike_bin_path:
MikePath.setup_mike_installation_custom(syspath)

@staticmethod
def setup_mike_installation_custom(syspath):
syspath.append(MikePath.mikeio1d_bin_path)

# Some of the MIKE libraries will need to be resolved by DHI.Mike.Install,
# so set it up here.
import clr
# Some of the MIKE libraries will need to be resolved by DHI.Mike.Install,
# so set it up here.
import clr

clr.AddReference(
"DHI.Mike.Install, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c513450b5d0bf0bf"
)
from DHI.Mike.Install import MikeImport
clr.AddReference(
"DHI.Mike.Install, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c513450b5d0bf0bf"
)
from DHI.Mike.Install import MikeImport

MikeImport.SetupInstallDir(MikePath.mike_install_path)

@staticmethod
def setup_mike_installation_linux():
# This mikecore import statement is for resolution of MIKE Core native libraries on Linux.
# Note that setting LD_LIBRARY_PATH in the process has no effect.
# The mikecore has patchelfed MIKE Core libraries,
# which helps to resolve them without LD_LIBRARY_PATH.
# Also it performs ctypes.CDLL statements to load the libraries
# and initialization of the libraries.
import mikecore

MikeImport.SetupInstallDir(mike_install_path)
runtime_config = os.path.join(
MikePath.mike_bin_path, "DHI.Mike1D.Application.runtimeconfig.json"
)
pythonnet.load("coreclr", runtime_config=runtime_config)
Loading

0 comments on commit 09273b7

Please sign in to comment.