diff --git a/README.md b/README.md index d9f2e34..75711ea 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Python development tools for MODFLOW 6. This is a small toolkit for developing MODFLOW 6, FloPy, and related projects. It includes standalone utilities and optional [Pytest](https://github.com/pytest-dev/pytest) extensions. -Standalone utilities include a very minimal GitHub API client, mainly for retrieving release information and downloading assets, and a `ZipFile` subclass that [preserves file permissions](https://stackoverflow.com/questions/39296101/python-zipfile-removes-execute-permissions-from-binaries) (workaround for [Python #15795](https://bugs.python.org/issue15795)) +The former include a very minimal GitHub API client for retrieving release information and downloading assets, a `ZipFile` subclass that [preserves file permissions](https://stackoverflow.com/questions/39296101/python-zipfile-removes-execute-permissions-from-binaries) (workaround for [Python #15795](https://bugs.python.org/issue15795)), and other release/distribution-related tools. Pytest features include: diff --git a/docs/md/ostags.md b/docs/md/ostags.md new file mode 100644 index 0000000..e140d98 --- /dev/null +++ b/docs/md/ostags.md @@ -0,0 +1,45 @@ +# OS Tags + +MODFLOW 6, Python3, build servers, and other systems may refer to operating systems by different names. Utilities are provided in the `modflow_devtools.ostags` module to convert between + +- the output of `platform.system()` +- GitHub Actions `runner.os` tags +- MODFLOW 6 release asset OS tags + +Only Linux, Mac and Windows are supported. + +## Tag specification + +Python3's `platform.system()` returns "Linux", "Darwin", and "Windows", respectively. + +GitHub Actions (e.g. `runner.os` context) use "Linux", "macOS" and "Windows". + +MODFLOW 6 release asset names end with "linux", "mac" or "win64". + +## Getting tags + +To get the MODFLOW 6 or GitHub tag for the current OS, use: + +- `get_modflow_ostag()` +- `get_github_ostag()` + +## Converting tags + +Conversion functions are available for each direction: + +- `python_to_modflow_ostag(tag)` +- `modflow_to_python_ostag(tag)` +- `modflow_to_github_ostag(tag)` +- `github_to_modflow_ostag(tag)` +- `python_to_github_ostag(tag)` +- `github_to_python_ostag(tag)` + +Alternatively: + +```python +OSTag.convert(platform.system(), "py2mf") +``` + +The second argument specifies the mapping in format `2`, where `` and `` may take values `py`, `mf`, or `gh`. + +**Note**: source and target must be different. diff --git a/modflow_devtools/ostags.py b/modflow_devtools/ostags.py new file mode 100644 index 0000000..55e7706 --- /dev/null +++ b/modflow_devtools/ostags.py @@ -0,0 +1,147 @@ +""" +MODFLOW 6, Python3, and build servers may all refer to operating +systems by different names. This module contains conversion utilities. +""" + + +from enum import Enum +from platform import system + +_system = system() + + +def get_modflow_ostag() -> str: + if _system == "Windows": + return "win64" + elif _system == "Linux": + return "linux" + elif _system == "Darwin": + return "mac" + else: + raise NotImplementedError(f"Unsupported system: {_system}") + + +def get_github_ostag() -> str: + if _system in ("Windows", "Linux"): + return _system + elif _system == "Darwin": + return "macOS" + else: + raise NotImplementedError(f"Unsupported system: {_system}") + + +def python_to_modflow_ostag(tag: str) -> str: + """ + Convert a platform.system() string to an ostag as expected + by MODFLOW 6. + + Parameters + ---------- + platform_system : str + The platform.system() string. + + Returns + ------- + str + """ + + if tag == "Windows": + return "win64" + elif tag == "Linux": + return "linux" + elif tag == "Darwin": + return "mac" + else: + raise ValueError(f"Invalid or unsupported tag: {tag}") + + +def modflow_to_python_ostag(tag: str) -> str: + """ + Convert a MODFLOW os tag to a platform.system() string. + + Parameters + ---------- + tag : str + The MODFLOW os tag. + + Returns + ------- + str + """ + + if tag == "win64": + return "Windows" + elif tag == "linux": + return "Linux" + elif tag == "mac": + return "Darwin" + else: + raise ValueError(f"Invalid or unsupported tag: {tag}") + + +def modflow_to_github_ostag(tag: str) -> str: + if tag == "win64": + return "Windows" + elif tag == "linux": + return "Linux" + elif tag == "mac": + return "macOS" + else: + raise ValueError(f"Invalid modflow os tag: {tag}") + + +def github_to_modflow_ostag(tag: str) -> str: + if tag == "Windows": + return "win64" + elif tag == "Linux": + return "linux" + elif tag == "macOS": + return "mac" + else: + raise ValueError(f"Invalid github os tag: {tag}") + + +def python_to_github_ostag(tag: str) -> str: + return modflow_to_github_ostag(python_to_modflow_ostag(tag)) + + +def github_to_python_ostag(tag: str) -> str: + return modflow_to_python_ostag(github_to_modflow_ostag(tag)) + + +def get_ostag(kind: str = "modflow") -> str: + if kind == "modflow": + return get_modflow_ostag() + elif kind == "github": + return get_github_ostag() + else: + raise ValueError(f"Invalid kind: {kind}") + + +class OSTagCvt(Enum): + py2mf = "py2mf" + mf2py = "mf2py" + gh2mf = "gh2mf" + mf2gh = "mf2gh" + py2gh = "py2gh" + gh2py = "gh2py" + + +class OSTag: + @staticmethod + def convert(tag: str, cvt: str) -> str: + cvt = OSTagCvt(cvt) + if cvt == OSTagCvt.py2mf: + return python_to_modflow_ostag(tag) + elif cvt == OSTagCvt.mf2py: + return modflow_to_python_ostag(tag) + elif cvt == OSTagCvt.gh2mf: + return github_to_modflow_ostag(tag) + elif cvt == OSTagCvt.mf2gh: + return modflow_to_github_ostag(tag) + elif cvt == OSTagCvt.py2gh: + return python_to_github_ostag(tag) + elif cvt == OSTagCvt.gh2py: + return github_to_python_ostag(tag) + else: + raise ValueError(f"Unsupported mapping: {cvt}") diff --git a/modflow_devtools/test/test_ostags.py b/modflow_devtools/test/test_ostags.py new file mode 100644 index 0000000..02d9adb --- /dev/null +++ b/modflow_devtools/test/test_ostags.py @@ -0,0 +1,55 @@ +from platform import system + +import pytest +from modflow_devtools.ostags import OSTag, get_github_ostag, get_modflow_ostag + +_system = system() + + +def test_get_modflow_ostag(): + t = get_modflow_ostag() + if _system == "Windows": + assert t == "win64" + elif _system == "Linux": + assert t == "linux" + elif _system == "Darwin": + assert t == "mac" + else: + pytest.skip(reason="Unsupported platform") + + +def test_get_github_ostag(): + t = get_github_ostag() + if _system in ("Windows", "Linux"): + assert t == _system + elif _system == "Darwin": + assert t == "macOS" + else: + pytest.skip(reason="Unsupported platform") + + +@pytest.mark.parametrize( + "cvt,tag,exp", + [ + ("py2mf", "Windows", "win64"), + ("mf2py", "win64", "Windows"), + ("py2mf", "Darwin", "mac"), + ("mf2py", "mac", "Darwin"), + ("py2mf", "Linux", "linux"), + ("mf2py", "linux", "Linux"), + ("gh2mf", "Windows", "win64"), + ("mf2gh", "win64", "Windows"), + ("gh2mf", "macOS", "mac"), + ("mf2gh", "mac", "macOS"), + ("gh2mf", "Linux", "linux"), + ("mf2gh", "linux", "Linux"), + ("py2gh", "Windows", "Windows"), + ("gh2py", "Windows", "Windows"), + ("py2gh", "Darwin", "macOS"), + ("gh2py", "macOS", "Darwin"), + ("py2gh", "Linux", "Linux"), + ("gh2py", "Linux", "Linux"), + ], +) +def test_ostag_convert(cvt, tag, exp): + assert OSTag.convert(tag, cvt) == exp