From 1cb7594d12a2aa385a567613e9f840de63ba7157 Mon Sep 17 00:00:00 2001 From: w-bonelli Date: Tue, 8 Aug 2023 10:03:11 -0400 Subject: [PATCH] feat(get-modflow): allow specifying repo owner (#1910) --- autotest/test_get_modflow.py | 21 +++++++++++++++------ docs/get_modflow.md | 4 +++- flopy/utils/get_modflow.py | 32 ++++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/autotest/test_get_modflow.py b/autotest/test_get_modflow.py index f7c3c7f124..3228dce218 100644 --- a/autotest/test_get_modflow.py +++ b/autotest/test_get_modflow.py @@ -27,6 +27,9 @@ / ("Scripts" if system() == "Windows" else "bin"), "home": Path.home() / ".local" / "bin", } +owner_options = [ + "MODFLOW-USGS", +] repo_options = { "executables": [ "crt", @@ -95,14 +98,14 @@ def append_ext(path: str): @pytest.mark.parametrize("per_page", [-1, 0, 101, 1000]) def test_get_releases_bad_page_size(per_page): with pytest.raises(ValueError): - get_releases("executables", per_page=per_page) + get_releases(repo="executables", per_page=per_page) @flaky @requires_github @pytest.mark.parametrize("repo", repo_options.keys()) def test_get_releases(repo): - releases = get_releases(repo) + releases = get_releases(repo=repo) assert "latest" in releases @@ -111,7 +114,7 @@ def test_get_releases(repo): @pytest.mark.parametrize("repo", repo_options.keys()) def test_get_release(repo): tag = "latest" - release = get_release(repo, tag) + release = get_release(repo=repo, tag=tag) assets = release["assets"] expected_assets = ["linux.zip", "mac.zip", "win64.zip"] @@ -245,11 +248,14 @@ def test_script_valid_options(function_tmpdir, downloads_dir): @flaky @requires_github @pytest.mark.slow +@pytest.mark.parametrize("owner", owner_options) @pytest.mark.parametrize("repo", repo_options.keys()) -def test_script(function_tmpdir, repo, downloads_dir): +def test_script(function_tmpdir, owner, repo, downloads_dir): bindir = str(function_tmpdir) stdout, stderr, returncode = run_get_modflow_script( bindir, + "--owner", + owner, "--repo", repo, "--downloads-dir", @@ -267,11 +273,14 @@ def test_script(function_tmpdir, repo, downloads_dir): @flaky @requires_github @pytest.mark.slow +@pytest.mark.parametrize("owner", owner_options) @pytest.mark.parametrize("repo", repo_options.keys()) -def test_python_api(function_tmpdir, repo, downloads_dir): +def test_python_api(function_tmpdir, owner, repo, downloads_dir): bindir = str(function_tmpdir) try: - get_modflow(bindir, repo=repo, downloads_dir=downloads_dir) + get_modflow( + bindir, owner=owner, repo=repo, downloads_dir=downloads_dir + ) except HTTPError as err: if err.code == 403: pytest.skip(f"GitHub {rate_limit_msg}") diff --git a/docs/get_modflow.md b/docs/get_modflow.md index 86a4ccc0b9..5e9cd3bcf1 100644 --- a/docs/get_modflow.md +++ b/docs/get_modflow.md @@ -73,7 +73,7 @@ Other auto-select options are only available if the current user can write files ## Selecting a distribution -By default the distribution from the [executables repository](https://github.com/MODFLOW-USGS/executables) is installed. This includes the MODFLOW 6 binary `mf6` and over 20 other related programs. The utility can also install from the main [MODFLOW 6 repo](https://github.com/MODFLOW-USGS/modflow6) or the [nightly build](https://github.com/MODFLOW-USGS/modflow6-nightly-build) distributions, which contain only: +By default the distribution from the [`MODFLOW-USGS/executables` repository](https://github.com/MODFLOW-USGS/executables) is installed. This includes the MODFLOW 6 binary `mf6` and over 20 other related programs. The utility can also install from the main [MODFLOW 6 repo](https://github.com/MODFLOW-USGS/modflow6) or the [nightly build](https://github.com/MODFLOW-USGS/modflow6-nightly-build) distributions, which contain only: - `mf6` - `mf5to6` @@ -85,3 +85,5 @@ To select a distribution, specify a repository name with the `--repo` command li - `executables` (default) - `modflow6` - `modflow6-nightly-build` + +The repository owner can also be configured with the `--owner` option. This can be useful for installing from unreleased MODFLOW 6 feature branches still in development — the only compatibility requirement is that release assets be named identically to those on the official repositories. diff --git a/flopy/utils/get_modflow.py b/flopy/utils/get_modflow.py index 2c979e163e..54c2a7d12c 100755 --- a/flopy/utils/get_modflow.py +++ b/flopy/utils/get_modflow.py @@ -24,7 +24,8 @@ from typing import Dict, List, Tuple -owner = "MODFLOW-USGS" +default_owner = "MODFLOW-USGS" +default_repo = "executables" # key is the repo name, value is the renamed file prefix for the download renamed_prefix = { "modflow6": "modflow6", @@ -93,8 +94,12 @@ def get_request(url, params={}): return urllib.request.Request(url, headers=headers) -def get_releases(repo, quiet=False, per_page=None) -> List[str]: +def get_releases( + owner=None, repo=None, quiet=False, per_page=None +) -> List[str]: """Get list of available releases.""" + owner = default_owner if owner is None else owner + repo = default_repo if repo is None else repo req_url = f"https://api.github.com/repos/{owner}/{repo}/releases" params = {} @@ -133,8 +138,10 @@ def get_releases(repo, quiet=False, per_page=None) -> List[str]: return avail_releases -def get_release(repo, tag="latest", quiet=False) -> dict: +def get_release(owner=None, repo=None, tag="latest", quiet=False) -> dict: """Get info about a particular release.""" + owner = default_owner if owner is None else owner + repo = default_repo if repo is None else repo api_url = f"https://api.github.com/repos/{owner}/{repo}" req_url = ( f"{api_url}/releases/latest" @@ -166,7 +173,7 @@ def get_release(repo, tag="latest", quiet=False) -> dict: ) from err elif err.code == 404: if releases is None: - releases = get_releases(repo, quiet) + releases = get_releases(owner, repo, quiet) if tag not in releases: raise ValueError( f"Release {tag} not found (choose from {', '.join(releases)})" @@ -287,7 +294,8 @@ def select_bindir(bindir, previous=None, quiet=False, is_cli=False) -> Path: def run_main( bindir, - repo="executables", + owner=default_owner, + repo=default_repo, release_id="latest", ostag=None, subset=None, @@ -304,6 +312,8 @@ def run_main( Writable path to extract executables. Auto-select options start with a colon character. See error message or other documentation for further information on auto-select options. + owner : str, default "MODFLOW-USGS" + Name of GitHub repository owner (user or organization). repo : str, default "executables" Name of GitHub repository. Choose one of "executables" (default), "modflow6", or "modflow6-nightly-build". @@ -393,7 +403,7 @@ def run_main( ) # get the selected release - release = get_release(repo, release_id, quiet) + release = get_release(owner, repo, release_id, quiet) assets = release.get("assets", []) for asset in assets: @@ -683,11 +693,17 @@ def cli_main(): "Option ':system' is '/usr/local/bin'." ) parser.add_argument("bindir", help=bindir_help) + parser.add_argument( + "--owner", + type=str, + default=default_owner, + help=f"GitHub repository owner; default is '{default_owner}'.", + ) parser.add_argument( "--repo", choices=available_repos, - default="executables", - help="Name of GitHub repository; default is 'executables'.", + default=default_repo, + help=f"Name of GitHub repository; default is '{default_repo}'.", ) parser.add_argument( "--release-id",