-
Notifications
You must be signed in to change notification settings - Fork 22
Fold fre pp rename-split into fre pp split-netcdf --rename
#783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Copilot
wants to merge
13
commits into
main
Choose a base branch
from
copilot/noaa-gfdl-717-fold-rename-split
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
487425b
Initial plan
Copilot d8dae1d
Merge branch 'rename-split' into copilot/noaa-gfdl-717-fold-rename-split
Copilot 77cb692
Fold rename-split into split-netcdf --rename flag with CLI and unit t…
Copilot 0b895cd
Address code review: fix typo and add error handling for rename rollback
Copilot e7b8c47
Address review: move rename logic into split_file_xarray, use fixture…
Copilot 0a41b94
Move rename_split_script import to top of split_netcdf_script.py
Copilot 1d80fe5
Convert split_file_xarray to 4-space indentation
Copilot e3a7474
Improve documentation for output directory structure
ilaflott 1c81d7c
Clarify ncgen_setup fixture purpose with comment
ilaflott 4f655d2
Write directly to final renamed path (no write + copy + delete)
Copilot 6b2b43e
Merge rename tests into test_split_netcdf.py, delete separate file
Copilot 73a872d
Add try/finally for decoded_dataset cleanup, improve error messages
Copilot a38af69
Merge branch 'main' into copilot/noaa-gfdl-717-fold-rename-split
ilaflott File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| ''' | ||
| Tests split-netcdf with --rename flag. | ||
| Tests the combined split + rename functionality that reorganizes | ||
| split netcdf files into a nested directory structure with frequency and duration. | ||
|
|
||
| Uses the existing split-netcdf test data (atmos_daily, ocean_static) to verify | ||
| the --rename flag behavior via direct import. | ||
| CLI tests (CliRunner) are in fre/tests/test_fre_pp_cli.py. | ||
| ''' | ||
|
|
||
| import pytest | ||
| import subprocess | ||
| import os | ||
| from os import path as osp | ||
| import shutil | ||
| from pathlib import Path | ||
| from fre.pp import split_netcdf_script | ||
| from fre.pp import rename_split_script | ||
|
|
||
| test_dir = osp.realpath("fre/tests/test_files/ascii_files/split_netcdf") | ||
|
|
||
| cases = {"ts": {"dir": "atmos_daily.tile3", | ||
| "nc": "00010101.atmos_daily.tile3.nc", | ||
| "cdl": "00010101.atmos_daily.tile3.cdl"}, | ||
| "static": {"dir": "ocean_static", | ||
| "nc": "00010101.ocean_static.nc", | ||
| "cdl": "00010101.ocean_static.cdl"}} | ||
|
|
||
|
|
||
| @pytest.fixture(scope="module") | ||
ilaflott marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| def ncgen_setup(): | ||
| '''Generates netcdf files from cdl test data needed for split+rename testing.''' | ||
| nc_files = [] | ||
| for testcase in cases.keys(): | ||
| cds = osp.join(test_dir, cases[testcase]["dir"]) | ||
| nc_path = osp.join(cds, cases[testcase]["nc"]) | ||
| cdl_path = osp.join(cds, cases[testcase]["cdl"]) | ||
| subprocess.run(["ncgen3", "-k", "netCDF-4", "-o", nc_path, cdl_path], | ||
| check=True, capture_output=True) | ||
| nc_files.append(nc_path) | ||
| yield nc_files | ||
| for nc in nc_files: | ||
| if osp.isfile(nc): | ||
| os.unlink(nc) | ||
|
|
||
|
|
||
| def test_split_rename_import_ts(ncgen_setup, tmp_path): | ||
| '''Tests split+rename via direct import for timeseries data. | ||
|
|
||
| Uses split_file_xarray with rename=True directly. | ||
| ''' | ||
| workdir = osp.join(test_dir, cases["ts"]["dir"]) | ||
| infile = osp.join(workdir, cases["ts"]["nc"]) | ||
| outfiledir = str(tmp_path / "import_ts") | ||
|
|
||
| split_netcdf_script.split_file_xarray(infile, outfiledir, "all", | ||
| rename=True) | ||
|
|
||
| outpath = Path(outfiledir) | ||
|
|
||
| # Verify no flat .nc files remain at root | ||
| root_nc_files = list(outpath.glob("*.nc")) | ||
| assert len(root_nc_files) == 0, f"Flat .nc files remain at root: {root_nc_files}" | ||
|
|
||
| # Verify nested structure was created | ||
| nested_nc_files = list(outpath.rglob("*.nc")) | ||
| assert len(nested_nc_files) > 0, "No .nc files found in nested structure" | ||
|
|
||
| # Verify component directory | ||
| component_dir = outpath / "atmos_daily" | ||
| assert component_dir.is_dir(), f"Component directory {component_dir} not found" | ||
|
|
||
| # Verify depth (component/freq/duration/file.nc) | ||
| for nc_file in nested_nc_files: | ||
| rel_path = nc_file.relative_to(outpath) | ||
| parts = rel_path.parts | ||
| assert len(parts) >= 4, \ | ||
| f"File {nc_file} is not deep enough: {parts}" | ||
|
|
||
|
|
||
| def test_split_rename_import_static(ncgen_setup, tmp_path): | ||
| '''Tests split+rename via direct import for static data. | ||
|
|
||
| Uses split_file_xarray with rename=True directly. | ||
| ''' | ||
| workdir = osp.join(test_dir, cases["static"]["dir"]) | ||
| infile = osp.join(workdir, cases["static"]["nc"]) | ||
| outfiledir = str(tmp_path / "import_static") | ||
|
|
||
| split_netcdf_script.split_file_xarray(infile, outfiledir, "all", | ||
| rename=True) | ||
|
|
||
| outpath = Path(outfiledir) | ||
|
|
||
| # Verify no flat .nc files remain at root | ||
| root_nc_files = list(outpath.glob("*.nc")) | ||
| assert len(root_nc_files) == 0, f"Flat .nc files remain at root: {root_nc_files}" | ||
|
|
||
| # Verify nested structure was created | ||
| nested_nc_files = list(outpath.rglob("*.nc")) | ||
| assert len(nested_nc_files) > 0, "No .nc files found in nested structure" | ||
|
|
||
| # Verify component directory | ||
| component_dir = outpath / "ocean_static" | ||
| assert component_dir.is_dir(), f"Component directory {component_dir} not found" | ||
|
|
||
| # Verify depth (component/P0Y/P0Y/file.nc) | ||
| for nc_file in nested_nc_files: | ||
| rel_path = nc_file.relative_to(outpath) | ||
| parts = rel_path.parts | ||
| assert len(parts) >= 4, \ | ||
| f"File {nc_file} is not deep enough: {parts}" | ||
|
|
||
|
|
||
| def test_split_rename_without_flag(ncgen_setup, tmp_path): | ||
| '''Tests that split_file_xarray without rename produces flat output (no nesting). | ||
|
|
||
| This verifies backward compatibility. | ||
| ''' | ||
| workdir = osp.join(test_dir, cases["ts"]["dir"]) | ||
| infile = osp.join(workdir, cases["ts"]["nc"]) | ||
| outfiledir = str(tmp_path / "no_rename") | ||
|
|
||
| split_netcdf_script.split_file_xarray(infile, outfiledir, "all") | ||
|
|
||
| outpath = Path(outfiledir) | ||
| # Verify flat .nc files exist at root (no nesting) | ||
| root_nc_files = list(outpath.glob("*.nc")) | ||
| assert len(root_nc_files) > 0, "No flat .nc files at root without rename" | ||
|
|
||
| # Verify no subdirectories were created | ||
| subdirs = [d for d in outpath.iterdir() if d.is_dir()] | ||
| assert len(subdirs) == 0, f"Subdirs created without rename: {subdirs}" | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| import os | ||
| import shutil | ||
| import subprocess | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
| from click.testing import CliRunner | ||
|
|
||
| from fre import fre | ||
|
|
@@ -213,3 +215,90 @@ def test_cli_fre_pp_split_netcdf_opt_dne(): | |
| ''' fre pp split-netcdf optionDNE ''' | ||
| result = runner.invoke(fre.fre, args=["pp", "split-netcdf", "optionDNE"]) | ||
| assert result.exit_code == 2 | ||
|
|
||
| def test_cli_fre_pp_split_netcdf_rename_help(): | ||
| ''' fre pp split-netcdf --help includes --rename option ''' | ||
| result = runner.invoke(fre.fre, args=["pp", "split-netcdf", "--help"]) | ||
| assert result.exit_code == 0 | ||
| assert "--rename" in result.output | ||
|
|
||
| def test_cli_fre_pp_split_netcdf_diag_manifest_help(): | ||
| ''' fre pp split-netcdf --help includes --diag-manifest option ''' | ||
| result = runner.invoke(fre.fre, args=["pp", "split-netcdf", "--help"]) | ||
| assert result.exit_code == 0 | ||
| assert "--diag-manifest" in result.output | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This and the new test above it do not test anything other than the existence of the click options! |
||
|
|
||
|
|
||
| #-- fre pp split-netcdf --rename (CLI functional tests) | ||
|
|
||
| SPLIT_NETCDF_TEST_DIR = os.path.realpath("fre/tests/test_files/ascii_files/split_netcdf") | ||
| SPLIT_RENAME_CASES = { | ||
| "ts": {"dir": "atmos_daily.tile3", | ||
| "nc": "00010101.atmos_daily.tile3.nc", | ||
| "cdl": "00010101.atmos_daily.tile3.cdl", | ||
| "component": "atmos_daily"}, | ||
| "static": {"dir": "ocean_static", | ||
| "nc": "00010101.ocean_static.nc", | ||
| "cdl": "00010101.ocean_static.cdl", | ||
| "component": "ocean_static"} | ||
| } | ||
|
|
||
| @pytest.fixture(scope="module") | ||
| def split_rename_ncgen(): | ||
| '''Generates netcdf files from cdl test data for split --rename CLI tests.''' | ||
| nc_files = [] | ||
| for testcase in SPLIT_RENAME_CASES.values(): | ||
| cds = os.path.join(SPLIT_NETCDF_TEST_DIR, testcase["dir"]) | ||
| nc_path = os.path.join(cds, testcase["nc"]) | ||
| cdl_path = os.path.join(cds, testcase["cdl"]) | ||
| subprocess.run(["ncgen3", "-k", "netCDF-4", "-o", nc_path, cdl_path], | ||
| check=True, capture_output=True) | ||
| nc_files.append(nc_path) | ||
| yield nc_files | ||
| for nc in nc_files: | ||
| if os.path.isfile(nc): | ||
| os.unlink(nc) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("case_key", ["ts", "static"]) | ||
ilaflott marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| def test_cli_fre_pp_split_netcdf_rename_run(split_rename_ncgen, tmp_path, case_key): | ||
| ''' fre pp split-netcdf --rename runs successfully via CLI ''' | ||
| case = SPLIT_RENAME_CASES[case_key] | ||
| workdir = os.path.join(SPLIT_NETCDF_TEST_DIR, case["dir"]) | ||
| infile = os.path.join(workdir, case["nc"]) | ||
| outfiledir = str(tmp_path / f"rename_{case_key}") | ||
| result = runner.invoke(fre.fre, args=["pp", "split-netcdf", | ||
| "--file", infile, | ||
| "--outputdir", outfiledir, | ||
| "--variables", "all", | ||
| "--rename"]) | ||
| assert result.exit_code == 0 | ||
| outpath = Path(outfiledir) | ||
| component_dir = outpath / case["component"] | ||
| assert component_dir.is_dir(), f"Expected component directory {component_dir} not found" | ||
| root_nc_files = list(outpath.glob("*.nc")) | ||
| assert len(root_nc_files) == 0, f"Flat .nc files remain at root: {root_nc_files}" | ||
| nested_nc_files = list(outpath.rglob("*.nc")) | ||
| assert len(nested_nc_files) > 0, "No .nc files found in nested structure" | ||
| for nc_file in nested_nc_files: | ||
| rel_path = nc_file.relative_to(outpath) | ||
| assert len(rel_path.parts) >= 4, \ | ||
| f"File {nc_file} not deep enough: {rel_path.parts}" | ||
|
|
||
|
|
||
| def test_cli_fre_pp_split_netcdf_no_rename(split_rename_ncgen, tmp_path): | ||
| ''' fre pp split-netcdf without --rename produces flat output ''' | ||
| case = SPLIT_RENAME_CASES["ts"] | ||
| workdir = os.path.join(SPLIT_NETCDF_TEST_DIR, case["dir"]) | ||
| infile = os.path.join(workdir, case["nc"]) | ||
| outfiledir = str(tmp_path / "no_rename") | ||
| result = runner.invoke(fre.fre, args=["pp", "split-netcdf", | ||
| "--file", infile, | ||
| "--outputdir", outfiledir, | ||
| "--variables", "all"]) | ||
| assert result.exit_code == 0 | ||
| outpath = Path(outfiledir) | ||
| root_nc_files = list(outpath.glob("*.nc")) | ||
| assert len(root_nc_files) > 0, "No flat .nc files at root without --rename" | ||
| subdirs = [d for d in outpath.iterdir() if d.is_dir()] | ||
| assert len(subdirs) == 0, f"Subdirs created without --rename: {subdirs}" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"During splitting", not "after splitting", to make it clear it's a single operation not two.