From 4718e2f3cfdabfe6c49f60d7945bedadab3eee3f Mon Sep 17 00:00:00 2001 From: Brioch Date: Tue, 11 Nov 2025 23:51:24 +0000 Subject: [PATCH 01/16] trying to get nightly pestpp builds on CI -- scary --- .github/workflows/ci.yml | 2 +- autotest/get_pestpp_tests.py | 31 +++++++++++++++++++++++++------ pyemu/utils/get_pestpp.py | 17 +++++++++-------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f7012e12..8e05b79a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,7 +118,7 @@ jobs: - name: Install PEST++ suite using get-pestpp shell: bash -l {0} run: | - get-pestpp :home + get-pestpp --owner pestpp -repo pestpp-nightly-builds :home env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/autotest/get_pestpp_tests.py b/autotest/get_pestpp_tests.py index d8bd280ff..91405ecd8 100644 --- a/autotest/get_pestpp_tests.py +++ b/autotest/get_pestpp_tests.py @@ -27,7 +27,7 @@ "home": Path.home() / ".local" / "bin", } owner_options = [ - "usgs", + "usgs", "pestpp" ] repo_options = { "pestpp": [ @@ -40,6 +40,16 @@ "pestpp-sqp", "pestpp-swp", ], + "pestpp-nightly-builds": [ + "pestpp-da", + "pestpp-glm", + "pestpp-ies", + "pestpp-mou", + "pestpp-opt", + "pestpp-sen", + "pestpp-sqp", + "pestpp-swp" + ] } if system() == "Windows": @@ -238,7 +248,10 @@ def test_script_valid_options(function_tmpdir, downloads_dir): @requires_github @pytest.mark.parametrize("owner", owner_options) @pytest.mark.parametrize("repo", repo_options.keys()) -def test_script(function_tmpdir, owner, repo, downloads_dir): +def test_script(request, function_tmpdir, owner, repo, downloads_dir): + if ((repo == "pestpp-nightly-builds" and owner != "pestpp") or + (owner == "pestpp" and repo != "pestpp-nightly-builds")): + request.applymarker(pytest.mark.xfail) bindir = str(function_tmpdir) stdout, stderr, returncode = run_get_pestpp_script( bindir, @@ -251,7 +264,8 @@ def test_script(function_tmpdir, owner, repo, downloads_dir): ) if rate_limit_msg in stderr: pytest.skip(f"GitHub {rate_limit_msg}") - + if returncode != 0: + raise RuntimeError(stderr) paths = list(function_tmpdir.glob("*")) names = [p.name for p in paths] expected_names = [append_ext(p) for p in repo_options[repo]] @@ -262,13 +276,18 @@ def test_script(function_tmpdir, owner, repo, downloads_dir): @requires_github @pytest.mark.parametrize("owner", owner_options) @pytest.mark.parametrize("repo", repo_options.keys()) -def test_python_api(function_tmpdir, owner, repo, downloads_dir): +def test_python_api(request, function_tmpdir, owner, repo, downloads_dir): + if ((repo == "pestpp-nightly-builds" and owner != "pestpp") or + (owner == "pestpp" and repo != "pestpp-nightly-builds")): + request.applymarker(pytest.mark.xfail) bindir = str(function_tmpdir) try: get_pestpp(bindir, owner=owner, repo=repo, downloads_dir=downloads_dir) - except HTTPError as err: - if err.code == 403: + except (HTTPError, IOError) as err: + if '403' in str(err): pytest.skip(f"GitHub {rate_limit_msg}") + else: + raise err paths = list(function_tmpdir.glob("*")) names = [p.name for p in paths] diff --git a/pyemu/utils/get_pestpp.py b/pyemu/utils/get_pestpp.py index 5f4bde045..393e36691 100755 --- a/pyemu/utils/get_pestpp.py +++ b/pyemu/utils/get_pestpp.py @@ -30,6 +30,7 @@ # key is the repo name, value is the renamed file prefix for the download renamed_prefix = { "pestpp": "pestpp", + "pestpp-nightly-builds": "pestpp", } available_repos = list(renamed_prefix.keys()) available_ostags = ["linux", "mac", "win"] @@ -165,9 +166,9 @@ def get_release(owner=None, repo=None, tag="latest", quiet=False) -> dict: break except urllib.error.HTTPError as err: if err.code == 401 and os.environ.get("GITHUB_TOKEN"): - raise ValueError("GITHUB_TOKEN env is invalid") from err + raise IOError("GITHUB_TOKEN env is invalid") from err elif err.code == 403 and "rate limit exceeded" in err.reason: - raise ValueError( + raise IOError( f"use GITHUB_TOKEN env to bypass rate limit ({err})" ) from err elif err.code == 404: @@ -425,13 +426,13 @@ def run_main( ) asset_name = asset["name"] download_url = asset["browser_download_url"] + asset_pth = Path(asset_name) + asset_stem = asset_pth.stem + if str(asset_pth).endswith("tar.gz"): + asset_suffix = ".tar.gz" + else: + asset_suffix = asset_pth.suffix if repo == "pestpp": - asset_pth = Path(asset_name) - asset_stem = asset_pth.stem - if str(asset_pth).endswith("tar.gz"): - asset_suffix = ".tar.gz" - else: - asset_suffix = asset_pth.suffix dst_fname = "-".join([repo, release["tag_name"], ostag]) + asset_suffix else: # change local download name so it is more unique From 7e80e56b2d552e8430b980feac1fb0d9350895ad Mon Sep 17 00:00:00 2001 From: Brioch Date: Tue, 11 Nov 2025 23:54:59 +0000 Subject: [PATCH 02/16] trying to get nightly pestpp builds on CI -- scary --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e05b79a2..d76e58429 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,7 +118,7 @@ jobs: - name: Install PEST++ suite using get-pestpp shell: bash -l {0} run: | - get-pestpp --owner pestpp -repo pestpp-nightly-builds :home + get-pestpp --owner pestpp --repo pestpp-nightly-builds :home env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From ec26dc41090c446583467c2f4737d312bf02b225 Mon Sep 17 00:00:00 2001 From: Brioch Date: Wed, 12 Nov 2025 00:01:45 +0000 Subject: [PATCH 03/16] script test tweak --- autotest/get_pestpp_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autotest/get_pestpp_tests.py b/autotest/get_pestpp_tests.py index 91405ecd8..82196d52f 100644 --- a/autotest/get_pestpp_tests.py +++ b/autotest/get_pestpp_tests.py @@ -264,7 +264,7 @@ def test_script(request, function_tmpdir, owner, repo, downloads_dir): ) if rate_limit_msg in stderr: pytest.skip(f"GitHub {rate_limit_msg}") - if returncode != 0: + elif returncode != 0: raise RuntimeError(stderr) paths = list(function_tmpdir.glob("*")) names = [p.name for p in paths] From d6cb8a506f1cd6c240da809963af5d6b2bc2a98f Mon Sep 17 00:00:00 2001 From: Brioch Date: Wed, 12 Nov 2025 00:13:42 +0000 Subject: [PATCH 04/16] trying to get windows nightlies picked up --- pyemu/utils/get_pestpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyemu/utils/get_pestpp.py b/pyemu/utils/get_pestpp.py index 393e36691..344d0f3af 100755 --- a/pyemu/utils/get_pestpp.py +++ b/pyemu/utils/get_pestpp.py @@ -417,7 +417,7 @@ def run_main( } for asset in assets: - if inconsistent_ostag_dict[ostag] in asset["name"]: + if ostag in asset["name"] or inconsistent_ostag_dict[ostag] in asset["name"]: break else: raise ValueError( From 66539570820bd9697cc25cc185ee2f8799793ff3 Mon Sep 17 00:00:00 2001 From: Brioch Date: Wed, 12 Nov 2025 00:22:02 +0000 Subject: [PATCH 05/16] coping with nightly builds nested in dist in zip --- pyemu/utils/get_pestpp.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyemu/utils/get_pestpp.py b/pyemu/utils/get_pestpp.py index 344d0f3af..a57ff9564 100755 --- a/pyemu/utils/get_pestpp.py +++ b/pyemu/utils/get_pestpp.py @@ -530,11 +530,13 @@ def run_main( download_pth = zip_path with zipfile.ZipFile(download_pth, "r") as zipf: - # First gather files within internal directories named "bin" + # First gather files within internal directories named "bin" or "dist/*/" for pth in zipf.namelist(): p = Path(pth) if p.parent.name == "bin": full_path[p.name] = pth + elif p.parent.parent.name == "dist": + full_path[p.name] = pth files = set(full_path.keys()) if not files: From 28525a6802a3f89526eb2e5bbb05d31662261e14 Mon Sep 17 00:00:00 2001 From: Brioch Date: Wed, 12 Nov 2025 01:25:55 +0000 Subject: [PATCH 06/16] release test checker --- autotest/get_pestpp_tests.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/autotest/get_pestpp_tests.py b/autotest/get_pestpp_tests.py index 82196d52f..17c4f8f09 100644 --- a/autotest/get_pestpp_tests.py +++ b/autotest/get_pestpp_tests.py @@ -110,24 +110,16 @@ def test_get_release(repo): release_tag_name = release["tag_name"] expected_assets = [ - f"pestpp-{release_tag_name}-linux.tar.gz", - f"pestpp-{release_tag_name}-mac.tar.gz", - f"pestpp-{release_tag_name}-iwin.zip", + f"pestpp-{release_tag_name}-linux", + f"pestpp-{release_tag_name}-mac", + f"pestpp-{release_tag_name}-win", ] - expected_ostags = [a.replace(".zip", "") for a in expected_assets] - expected_ostags = [a.replace("tar.gz", "") for a in expected_assets] - actual_assets = [asset["name"] for asset in assets] - - if repo == "pestpp": - # can remove if modflow6 releases follow asset name conventions followed in executables and nightly build repos - assert {a.rpartition("_")[2] for a in actual_assets} >= { - a for a in expected_assets if not a.startswith("win") - } - else: - for ostag in expected_ostags: - assert any( - ostag in a for a in actual_assets - ), f"dist not found for {ostag}" + actual_assets = [asset["name"].replace("tar.gz", "").replace(".zip", "") for asset in assets] + + for ostag in expected_assets: + assert any( + ostag in a for a in actual_assets + ), f"dist not found for {ostag}" @pytest.mark.parametrize("bindir", bindir_options.keys()) From 16bdefdc9c54a86996e69c934f3bca2ac7f9aea8 Mon Sep 17 00:00:00 2001 From: Brioch Date: Wed, 12 Nov 2025 08:44:43 +0000 Subject: [PATCH 07/16] simplifying tests suite to chase another timeout issue --- .github/workflows/ci.yml | 9 ++++----- autotest/conftest.py | 26 +++++++++++++------------- autotest/utils_tests.py | 8 ++++---- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d76e58429..417c1c5fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,11 +17,11 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: [ - "3.10", - "3.11", - "3.12", +# "3.10", +# "3.11", +# "3.12", "3.13", - "3.14" +# "3.14" ] run-type: [std] test-path: ["autotest"] @@ -126,7 +126,6 @@ jobs: shell: bash -l {0} run: | pytest ${{ matrix.test-path }} \ - -n=auto \ -rA -vv --tb=native \ --durations=20 \ --cov=pyemu --cov-report=lcov diff --git a/autotest/conftest.py b/autotest/conftest.py index 5599e1bd6..2aef7dfa2 100644 --- a/autotest/conftest.py +++ b/autotest/conftest.py @@ -7,21 +7,21 @@ pytest_plugins = ["modflow_devtools.fixtures"] collect_ignore = [ - # "emulator_tests.py", - # "en_tests.py", - # "full_meal_deal_tests_2.py", + "emulator_tests.py", + "en_tests.py", + "full_meal_deal_tests_2.py", # "get_pestpp_tests.py", - # "la_tests.py", - # "mat_tests.py", - # "mc_tests_ignore.py", - # "metrics_tests.py", - # "plot_tests.py", - # "pst_from_tests.py", - # "pst_tests.py", - # "pst_tests_2.py", - # "transformer_tests.py", + "la_tests.py", + "mat_tests.py", + "mc_tests_ignore.py", + "metrics_tests.py", + "plot_tests.py", + "pst_from_tests.py", + "pst_tests.py", + "pst_tests_2.py", + "transformer_tests.py", # "utils_tests.py" - # "verf_test.py", + "verf_test.py", ] def get_project_root_path(): diff --git a/autotest/utils_tests.py b/autotest/utils_tests.py index 62e59b427..ffcdfeba5 100644 --- a/autotest/utils_tests.py +++ b/autotest/utils_tests.py @@ -2705,7 +2705,7 @@ def ppw_worker(id_num,case,t_d,host,port,frun): #print("worker",id_num,"finished run",ppw.net_pack.runid) -@pytest.mark.timeout(method="thread") +@pytest.mark.timeout(method="thread", timeout=300) def pypestworker_test(tmp_path): from datetime import datetime import numpy as np @@ -2734,11 +2734,11 @@ def pypestworker_test(tmp_path): from forward_run import helper as frun m_d = "{0}_ppw_master".format(case) - + if os.path.exists(m_d): shutil.rmtree(m_d) shutil.copytree(t_d,m_d) - + # start the master start = datetime.now() b_d = os.getcwd() @@ -2754,7 +2754,7 @@ def pypestworker_test(tmp_path): #return num_workers=5 - + # looper over and start the workers - in this # case they dont need unique dirs since they aren't writing # anything From 27c1aa7835f6e7e2ce841404e4557ad7b9cf52d5 Mon Sep 17 00:00:00 2001 From: Brioch Date: Wed, 12 Nov 2025 10:25:50 +0000 Subject: [PATCH 08/16] mods to get release to deal with diff defaults --- autotest/get_pestpp_tests.py | 6 +++++- pyemu/utils/get_pestpp.py | 21 +++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/autotest/get_pestpp_tests.py b/autotest/get_pestpp_tests.py index 17c4f8f09..521717273 100644 --- a/autotest/get_pestpp_tests.py +++ b/autotest/get_pestpp_tests.py @@ -107,7 +107,11 @@ def test_get_release(repo): tag = "latest" release = get_release(repo=repo, tag=tag) assets = release["assets"] - release_tag_name = release["tag_name"] + if len(release["body"]) > 0: + # if nightly build tag is in body, use that + release_tag_name = release["body"].split()[-1] + else: + release_tag_name = release["tag_name"] expected_assets = [ f"pestpp-{release_tag_name}-linux", diff --git a/pyemu/utils/get_pestpp.py b/pyemu/utils/get_pestpp.py index a57ff9564..85be64ebd 100755 --- a/pyemu/utils/get_pestpp.py +++ b/pyemu/utils/get_pestpp.py @@ -98,8 +98,7 @@ 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 + owner, repo = _get_defaults(owner, repo) req_url = f"https://api.github.com/repos/{owner}/{repo}/releases" params = {} @@ -138,10 +137,24 @@ def get_releases( return avail_releases +def _get_defaults(owner=None, repo=None): + """Get default owner and repo if not provided.""" + default_owner_dict = {'pestpp': "usgs", + 'pestpp-nightly-builds': "pestpp"} + default_repo_dict = {o: r for r, o in default_owner_dict.items()} + # if nothing passed + if owner is None and repo is None: + owner = default_owner + + if repo is None: + repo = default_repo_dict.get(owner, default_repo) + elif owner is None: + owner = default_owner_dict.get(repo, default_owner) + return owner, repo + 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 + owner, repo = _get_defaults(owner, repo) api_url = f"https://api.github.com/repos/{owner}/{repo}" req_url = ( f"{api_url}/releases/latest" From 9fc6d7825aa110bb9dda4f5c55007906493ad2d3 Mon Sep 17 00:00:00 2001 From: Brioch Date: Wed, 12 Nov 2025 16:51:42 +0000 Subject: [PATCH 09/16] Catch in ppw test for master fail. + SETTING XFAIL FOR TEST_PPW for now, until MOU update --- autotest/utils_tests.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/autotest/utils_tests.py b/autotest/utils_tests.py index ffcdfeba5..497a85fb7 100644 --- a/autotest/utils_tests.py +++ b/autotest/utils_tests.py @@ -2706,12 +2706,13 @@ def ppw_worker(id_num,case,t_d,host,port,frun): @pytest.mark.timeout(method="thread", timeout=300) -def pypestworker_test(tmp_path): +def test_pypestworker(request, tmp_path): from datetime import datetime import numpy as np import subprocess as sp import multiprocessing as mp import sys + import time host = "localhost" port = 4111 @@ -2744,7 +2745,8 @@ def pypestworker_test(tmp_path): b_d = os.getcwd() os.chdir(m_d) try: - p = sp.Popen([mou_exe_path, "{0}.pst".format(case), "/h", ":{0}".format(port)]) + p = sp.Popen([mou_exe_path, "{0}.pst".format(case), "/h", ":{0}".format(port)], + stdout=sp.PIPE, stderr=sp.PIPE) except Exception as e: print("failed to start master process") os.chdir(b_d) @@ -2758,9 +2760,21 @@ def pypestworker_test(tmp_path): # looper over and start the workers - in this # case they dont need unique dirs since they aren't writing # anything + # little pause to let master get going (and possibly fail) + time.sleep(5) procs = [] for i in range(num_workers): - pp = mp.Process(target=ppw_worker,args=(i,case,t_d,host,port,frun)) + # check master still running before deploying worker + if p.poll() is not None: + err = p.stderr.read() + # todo: remove this xfail in next (post 5.2.23dev20251209) pestpp release + if "wrong number of tokens on line 1 of file" in err.decode(): + request.applymarker(pytest.mark.xfail) + # todo: remove this xfail in next (post 5.2.23dev20251209) pestpp release + raise RuntimeError("master process failed before all workers started:\n\n"+ + err.decode()) + pp = mp.Process(target=ppw_worker,args=(i,case,t_d,host,port,frun), kwargs={'master_process':p}) + # procs.append(pp) pp.start() procs.append(pp) # if everything worked, the workers should receive the From 471b70a4f3ecb57d0656a56fb14ea49915321014 Mon Sep 17 00:00:00 2001 From: Brioch Date: Wed, 12 Nov 2025 17:07:27 +0000 Subject: [PATCH 10/16] all tests and py versions --- .github/workflows/ci.yml | 9 +++++---- autotest/conftest.py | 26 +++++++++++++------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 417c1c5fb..d76e58429 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,11 +17,11 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: [ -# "3.10", -# "3.11", -# "3.12", + "3.10", + "3.11", + "3.12", "3.13", -# "3.14" + "3.14" ] run-type: [std] test-path: ["autotest"] @@ -126,6 +126,7 @@ jobs: shell: bash -l {0} run: | pytest ${{ matrix.test-path }} \ + -n=auto \ -rA -vv --tb=native \ --durations=20 \ --cov=pyemu --cov-report=lcov diff --git a/autotest/conftest.py b/autotest/conftest.py index 2aef7dfa2..5599e1bd6 100644 --- a/autotest/conftest.py +++ b/autotest/conftest.py @@ -7,21 +7,21 @@ pytest_plugins = ["modflow_devtools.fixtures"] collect_ignore = [ - "emulator_tests.py", - "en_tests.py", - "full_meal_deal_tests_2.py", + # "emulator_tests.py", + # "en_tests.py", + # "full_meal_deal_tests_2.py", # "get_pestpp_tests.py", - "la_tests.py", - "mat_tests.py", - "mc_tests_ignore.py", - "metrics_tests.py", - "plot_tests.py", - "pst_from_tests.py", - "pst_tests.py", - "pst_tests_2.py", - "transformer_tests.py", + # "la_tests.py", + # "mat_tests.py", + # "mc_tests_ignore.py", + # "metrics_tests.py", + # "plot_tests.py", + # "pst_from_tests.py", + # "pst_tests.py", + # "pst_tests_2.py", + # "transformer_tests.py", # "utils_tests.py" - "verf_test.py", + # "verf_test.py", ] def get_project_root_path(): From b8532b9180472fe800662342cbe6a79841547bea Mon Sep 17 00:00:00 2001 From: Brioch Date: Thu, 13 Nov 2025 11:44:28 +0000 Subject: [PATCH 11/16] dialing in pestpp 5.2.24dev mou updates --- autotest/utils_tests.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/autotest/utils_tests.py b/autotest/utils_tests.py index 497a85fb7..16b02287d 100644 --- a/autotest/utils_tests.py +++ b/autotest/utils_tests.py @@ -2767,16 +2767,17 @@ def test_pypestworker(request, tmp_path): # check master still running before deploying worker if p.poll() is not None: err = p.stderr.read() - # todo: remove this xfail in next (post 5.2.23dev20251209) pestpp release - if "wrong number of tokens on line 1 of file" in err.decode(): - request.applymarker(pytest.mark.xfail) - # todo: remove this xfail in next (post 5.2.23dev20251209) pestpp release raise RuntimeError("master process failed before all workers started:\n\n"+ err.decode()) - pp = mp.Process(target=ppw_worker,args=(i,case,t_d,host,port,frun), kwargs={'master_process':p}) - # procs.append(pp) - pp.start() - procs.append(pp) + try: # make sure we kill the master if worker startup returns an error + pp = mp.Process(target=ppw_worker,args=(i,case,t_d,host,port,frun)) + # procs.append(pp) + pp.start() + procs.append(pp) + except Exception as e: + print("failed to start worker {0}".format(i)) + p.terminate() + raise e # if everything worked, the workers should receive the # shutdown signal from the master and exit gracefully... for pp in procs: From 08c99040b320ba0bd84c5a25be889bba573c8dd9 Mon Sep 17 00:00:00 2001 From: Brioch Date: Thu, 13 Nov 2025 12:30:55 +0000 Subject: [PATCH 12/16] just pypestworker on 3.13 -- checking timeout without xdist --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d76e58429..b655c01b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,11 +17,11 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: [ - "3.10", - "3.11", - "3.12", +# "3.10", +# "3.11", +# "3.12", "3.13", - "3.14" +# "3.14" ] run-type: [std] test-path: ["autotest"] @@ -126,10 +126,10 @@ jobs: shell: bash -l {0} run: | pytest ${{ matrix.test-path }} \ - -n=auto \ -rA -vv --tb=native \ --durations=20 \ --cov=pyemu --cov-report=lcov + -k "pypestworker" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MPLBACKEND: Agg # non-interactive backend for matplotlib From bf535b7e3b49dea79f994b6d34b593004256b246 Mon Sep 17 00:00:00 2001 From: Brioch Date: Thu, 13 Nov 2025 12:37:15 +0000 Subject: [PATCH 13/16] just pypestworker on 3.13 -- checking timeout without xdist --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b655c01b6..bfa86f96c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,7 +128,7 @@ jobs: pytest ${{ matrix.test-path }} \ -rA -vv --tb=native \ --durations=20 \ - --cov=pyemu --cov-report=lcov + --cov=pyemu --cov-report=lcov \ -k "pypestworker" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 36762ab5f37f5e396a56f20b40270b3f97c86f30 Mon Sep 17 00:00:00 2001 From: briochh Date: Thu, 13 Nov 2025 17:33:48 +0000 Subject: [PATCH 14/16] windows stdout->sp.PIPE issues --- autotest/utils_tests.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/autotest/utils_tests.py b/autotest/utils_tests.py index 16b02287d..55346111f 100644 --- a/autotest/utils_tests.py +++ b/autotest/utils_tests.py @@ -2734,7 +2734,7 @@ def test_pypestworker(request, tmp_path): sys.path.insert(1, t_d.as_posix()) from forward_run import helper as frun - m_d = "{0}_ppw_master".format(case) + m_d = tmp_path / "{0}_ppw_master".format(case) if os.path.exists(m_d): shutil.rmtree(m_d) @@ -2745,8 +2745,7 @@ def test_pypestworker(request, tmp_path): b_d = os.getcwd() os.chdir(m_d) try: - p = sp.Popen([mou_exe_path, "{0}.pst".format(case), "/h", ":{0}".format(port)], - stdout=sp.PIPE, stderr=sp.PIPE) + p = sp.Popen([mou_exe_path, "{0}.pst".format(case), "/h", ":{0}".format(port)], stderr=sp.PIPE) except Exception as e: print("failed to start master process") os.chdir(b_d) @@ -2780,8 +2779,13 @@ def test_pypestworker(request, tmp_path): raise e # if everything worked, the workers should receive the # shutdown signal from the master and exit gracefully... - for pp in procs: - pp.join() + for i, pp in enumerate(procs): + try: # make sure we kill the master if worker startup returns an error + pp.join() + except Exception as e: + print(f"exception thrown by worker {i}") + p.terminate() + raise e # wait for the master to finish...but should already be finished p.wait() From 59073282af602d833a747fd5a47489a974b5fd5a Mon Sep 17 00:00:00 2001 From: briochh Date: Thu, 13 Nov 2025 17:50:06 +0000 Subject: [PATCH 15/16] all tests and py --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfa86f96c..287ceaaf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,11 +17,11 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: [ -# "3.10", -# "3.11", -# "3.12", + "3.10", + "3.11", + "3.12", "3.13", -# "3.14" + "3.14" ] run-type: [std] test-path: ["autotest"] @@ -126,10 +126,10 @@ jobs: shell: bash -l {0} run: | pytest ${{ matrix.test-path }} \ + -n=auto \ -rA -vv --tb=native \ --durations=20 \ --cov=pyemu --cov-report=lcov \ - -k "pypestworker" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MPLBACKEND: Agg # non-interactive backend for matplotlib From 073c9d4f3e54553aea110f3cb0a3c9689d40a6b0 Mon Sep 17 00:00:00 2001 From: Brioch Date: Thu, 13 Nov 2025 23:37:31 +0000 Subject: [PATCH 16/16] loser on the ppw timeout --- autotest/utils_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autotest/utils_tests.py b/autotest/utils_tests.py index 55346111f..5c96f7ba0 100644 --- a/autotest/utils_tests.py +++ b/autotest/utils_tests.py @@ -2705,8 +2705,8 @@ def ppw_worker(id_num,case,t_d,host,port,frun): #print("worker",id_num,"finished run",ppw.net_pack.runid) -@pytest.mark.timeout(method="thread", timeout=300) -def test_pypestworker(request, tmp_path): +@pytest.mark.timeout(method="thread") +def test_pypestworker(tmp_path): from datetime import datetime import numpy as np import subprocess as sp