diff --git a/.github/workflows/marsformat_test.yml b/.github/workflows/marsformat_test.yml new file mode 100644 index 00000000..2492ca45 --- /dev/null +++ b/.github/workflows/marsformat_test.yml @@ -0,0 +1,77 @@ +name: MarsFormat Test Workflow + +on: + # Trigger the workflow on push to devel branch + push: + branches: [ devel ] + paths: + - 'bin/MarsFormat.py' + - 'tests/test_marsformat.py' + - '.github/workflows/marsformat_test.yml' + # Allow manual triggering of the workflow + workflow_dispatch: + # Trigger on pull requests that modify MarsFormat or tests + pull_request: + branches: [ devel ] + paths: + - 'bin/MarsFormat.py' + - 'tests/test_marsformat.py' + - '.github/workflows/marsformat_test.yml' + +jobs: + test: + # Run on multiple OS and Python versions for comprehensive testing + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.9', '3.10', '3.11'] + + runs-on: ${{ matrix.os }} + + steps: + # Checkout the repository + - uses: actions/checkout@v3 + + # Set up the specified Python version + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + + # Install dependencies + - name: Install dependencies + shell: bash + run: | + python -m pip install --upgrade pip + pip install numpy xarray netCDF4 matplotlib scipy + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + + # Install the package in editable mode + - name: Install package + run: pip install -e . + + # Set HOME for Windows since it might be used by the script + - name: Set HOME environment variable for Windows + if: runner.os == 'Windows' + shell: pwsh + run: | + echo "HOME=$env:USERPROFILE" >> $env:GITHUB_ENV + + # Set up AmesCAP configuration - handle platform differences + - name: Set up AmesCAP configuration + shell: bash + run: | + mkdir -p $HOME/.amescap + cp mars_templates/amescap_profile $HOME/.amescap_profile + + # Print out environment info + - name: Show environment info + run: | + python -c "import os, sys, numpy, netCDF4, xarray; print(f'Python: {sys.version}, NumPy: {numpy.__version__}, NetCDF4: {netCDF4.__version__}, xarray: {xarray.__version__}')" + echo "Working directory: $(pwd)" + echo "Home directory: $HOME" + echo "Environment variables: $(env)" + + # Run the tests + - name: Run MarsFormat tests + run: python -m unittest -v tests/test_marsformat.py \ No newline at end of file diff --git a/.github/workflows/marspull_test.yml b/.github/workflows/marspull_test.yml index 00a19ee5..ae8aa6d8 100644 --- a/.github/workflows/marspull_test.yml +++ b/.github/workflows/marspull_test.yml @@ -8,11 +8,9 @@ on: - 'bin/MarsPull.py' - 'tests/test_marspull.py' - '.github/workflows/marspull_test.yml' - # Allow manual triggering of the workflow workflow_dispatch: - - # Trigger on pull requests that modify MarsPull or tests + # Trigger on pull requests that modify MarsFormat or tests pull_request: branches: [ devel ] paths: @@ -25,7 +23,7 @@ jobs: # Run on multiple OS and Python versions for comprehensive testing strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] python-version: ['3.9', '3.10', '3.11'] runs-on: ${{ matrix.os }} @@ -42,6 +40,7 @@ jobs: # Install dependencies - name: Install dependencies + shell: bash run: | python -m pip install --upgrade pip pip install requests numpy @@ -53,5 +52,4 @@ jobs: # Run the tests - name: Run MarsPull tests - run: | - python -m unittest tests/test_marspull.py \ No newline at end of file + run: python -m unittest -v tests/test_marspull.py \ No newline at end of file diff --git a/bin/MarsFiles.py b/bin/MarsFiles.py index cd58c8ab..0f71f702 100755 --- a/bin/MarsFiles.py +++ b/bin/MarsFiles.py @@ -177,6 +177,7 @@ def wrapper(*args, **kwargs): f" - ``daily`` : instantaneous data\n" f" - ``diurn`` : 5-sol averages binned by time of day\n" f" - ``average``: 5-sol averages\n" + f"Works on 'fort.11' files only.\n" f"{Green}Example:\n" f"> MarsFiles fort.11_* -bin fixed daily diurn average\n" f"> MarsFiles fort.11_* -bin fixed diurn" @@ -187,7 +188,7 @@ def wrapper(*args, **kwargs): parser.add_argument('-c', '--concatenate', action='store_true', help=( f"Combine sequential files of the same type into one file.\n" - f"and ``diurn``).\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> ls\n" f"00334.atmos_average.nc 00668.atmos_average.nc\n" @@ -214,6 +215,7 @@ def wrapper(*args, **kwargs): f"Defaults to ``areo`` (Ls) unless otherwise specified using " f"-dim.\nIf a file contains multiple Mars Years of data, the " f"function splits the file in the first Mars Year.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_average.nc --split 0 90\n" f"> MarsFiles 01336.atmos_average.nc --split 270\n" @@ -232,6 +234,7 @@ def wrapper(*args, **kwargs): f"time.\nUseful for comparing data at a specific time of day " f"across all longitudes.\nWorks on vertically interpolated " f"files.\n" + f"Works on 'diurn' files only.\n" f"{Yellow}Generates a new file ending in ``_T.nc``{Nclr}\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_diurn.nc -t" @@ -253,7 +256,7 @@ def wrapper(*args, **kwargs): f"{Yellow}Generates a new file ending in ``_to_average.nc``\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_daily.nc -ba {Blue}(5-sol bin){Green}\n" - f"> MarsFiles 01336.atmos_daily_pstd.nc -ba 10 {Blue}(10-sol bin)" + f"> MarsFiles 01336.atmos_daily.nc -ba 10 {Blue}(10-sol bin)" f"{Nclr}\n\n" ) ) @@ -270,9 +273,9 @@ def wrapper(*args, **kwargs): f"{Yellow}Generates a new file ending in ``_to_diurn.nc``\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_daily.nc -bd {Blue}(5-sol bin){Green}\n" - f"> MarsFiles 01336.atmos_daily_pstd.nc -bd -ba 10 " + f"> MarsFiles 01336.atmos_daily.nc -bd -ba 10 " f"{Blue}(10-sol bin){Green}\n" - f"> MarsFiles 01336.atmos_daily_pstd.nc -bd -ba 1 " + f"> MarsFiles 01336.atmos_daily.nc -bd -ba 1 " f"{Blue}(no binning, mimics raw Legacy output)" f"{Nclr}\n\n" ) @@ -284,9 +287,9 @@ def wrapper(*args, **kwargs): nargs='+', type=float, help=( f"Temporal high-pass filtering: removes low-frequencies \n" - f"Only works with 'daily' or 'average' files. Requires a cutoff frequency " - f"in Sols.\n" - f"Data is detrended before filtering. Use ``--add_trend`` \n" + f"Only works with 'daily' or 'average' files. Requires a cutoff " + f"frequency in Sols.\n" + f"Data is detrended before filtering. Use ``-add_trend`` \n" f"to add the original linear trend to the amplitudes \n" f"\n{Yellow}Generates a new file ending in ``_hpt.nc``\n" f"{Green}Example:\n" @@ -301,9 +304,9 @@ def wrapper(*args, **kwargs): nargs='+', type=float, help=( f"Temporal low-pass filtering: removes high-frequencies \n" - f"Only works with 'daily' or 'average' files. Requires a cutoff frequency " - f"in Sols.\n" - f"Data is detrended before filtering. Use ``--add_trend`` \n" + f"Only works with 'daily' or 'average' files. Requires a cutoff " + f"frequency in Sols.\n" + f"Data is detrended before filtering. Use ``-add_trend`` \n" f"to add the original linear trend to the amplitudes \n" f"\n{Yellow}Generates a new file ending in ``_lpt.nc``\n" f"{Green}Example:\n" @@ -320,7 +323,7 @@ def wrapper(*args, **kwargs): f"Temporal band-pass filtering" f"specified by user.\nOnly works with 'daily' or 'average' " f"files. Requires two cutoff frequencies in Sols.\n" - f"Data is detrended before filtering. Use ``--add_trend`` \n" + f"Data is detrended before filtering. Use ``-add_trend`` \n" f"to add the original linear trend to the amplitudes \n" f"\n{Yellow}Generates a new file ending in ``bpt.nc``\n" f"{Green}Example:\n" @@ -340,7 +343,7 @@ def wrapper(*args, **kwargs): f"in Sols.\n" f"{Yellow}Generates a new file ending in ``_hps.nc``\n" f"{Green}Example:\n" - f"> MarsFiles 01336.atmos_daily.nc -hps 10 --add_trend\n" + f"> MarsFiles 01336.atmos_daily.nc -hps 10 -add_trend\n" f"{Nclr}\n\n" ) ) @@ -355,7 +358,7 @@ def wrapper(*args, **kwargs): f"cutoff frequency in Sols.\n" f"{Yellow}Generates a new file ending in ``_lps.nc``\n" f"{Green}Example:\n" - f"> MarsFiles 01336.atmos_daily.nc -lps 20 --add_trend\n" + f"> MarsFiles 01336.atmos_daily.nc -lps 20 -add_trend\n" f"{Nclr}\n\n" ) ) @@ -370,7 +373,7 @@ def wrapper(*args, **kwargs): f"cutoff frequency in Sols.\nData detrended before filtering.\n" f"{Yellow}Generates a new file ending in ``_bps.nc``\n" f"{Green}Example:\n" - f"> MarsFiles 01336.atmos_daily.nc -bps 10 20 --add_trend\n" + f"> MarsFiles 01336.atmos_daily.nc -bps 10 20 -add_trend\n" f"{Nclr}\n\n" ) ) @@ -384,6 +387,7 @@ def wrapper(*args, **kwargs): f"harmonics.\nOnly works with 'diurn' files.\nReturns the phase " f"and amplitude of the variable.\n" f"N = 1 diurnal tide, N = 2 semi-diurnal, etc.\n" + f"Works on 'diurn' files only.\n" f"{Yellow}Generates a new file ending in ``_tide_decomp.nc``\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_diurn.nc -tide 2 -incl ps temp\n" @@ -402,6 +406,7 @@ def wrapper(*args, **kwargs): f"user-provided source file.\nBoth files must have the same " f"vertical dimensions (i.e., should be vertically\ninterpolated " f"to the same standard grid [zstd, zagl, pstd, etc.].\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Yellow}Generates a new file ending in ``_regrid.nc``\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_average_pstd.nc -regrid " @@ -421,6 +426,7 @@ def wrapper(*args, **kwargs): f"Zonally average the entire file over the longitudinal " f"dimension.\nDoes not work if the longitude dimension has " f"length <= 1.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Yellow}Generates a new file ending in ``_zavg.nc``\n" f"{Green}Example:\n" "> MarsFiles 01336.atmos_diurn.nc -zavg" @@ -435,6 +441,7 @@ def wrapper(*args, **kwargs): f"Must be used with [-split --split]. Flag indicates the " f"dimension on which to trim the file.\nAcceptable values are " f"'areo', 'lev', 'lat', 'lon'. Default = 'areo'.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_average.nc --split 0 90 -dim areo\n" f"> MarsFiles 01336.atmos_average.nc --split -70 -dim lat" @@ -450,6 +457,7 @@ def wrapper(*args, **kwargs): f"For use with ``-tide``: Returns the result in percent " f"amplitude.\n" f"N = 1 diurnal tide, N = 2 semi-diurnal, etc.\n" + f"Works on 'diurn' files only.\n" f"{Yellow}Generates a new file ending in ``_norm.nc``\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_diurn.nc -tide 6 -incl ps " @@ -482,6 +490,7 @@ def wrapper(*args, **kwargs): nargs=0, help=( f"Reconstructs the first N harmonics.\n" + f"Works on 'diurn' files only.\n" f"{Yellow}Generates a new file ending in ``_reconstruct.nc``\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_diurn.nc -tide 6 -incl ps temp " @@ -495,8 +504,7 @@ def wrapper(*args, **kwargs): f"Flag to use only the variables specified in a calculation.\n" f"All dimensional and 1D variables are ported to the new file " f"automatically.\n" - f"{Yellow}Overwrites existing target file. To override, use " - f"-ext.{Nclr}\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsFiles 01336.atmos_daily.nc -ba -incl ps temp ts" f"{Nclr}\n\n" @@ -510,8 +518,8 @@ def wrapper(*args, **kwargs): f"CAP to create a new file with the extension name specified " f"here.\n" f"{Green}Example:\n" - f"> MarsFiles 00334.atmos_average.nc -c -ext _comb\n" - f"{Blue}(Produces 00334.atmos_average_comb.nc and " + f"> MarsFiles 01336.atmos_average.nc -c -ext _my_concat\n" + f"{Blue}(Produces 01336.atmos_average_my_concat.nc and " f"preserves all other files)" f"{Nclr}\n\n" ) diff --git a/bin/MarsFormat.py b/bin/MarsFormat.py index 40866555..53549534 100755 --- a/bin/MarsFormat.py +++ b/bin/MarsFormat.py @@ -125,6 +125,7 @@ def wrapper(*args, **kwargs): help=( f"Calculate 5-day averages binned by hour from instantaneous " f"data. Generates MGCM-like 'diurn' files.\n" + f"Works on non-MGCM files only.\n" f"{Green}Example:\n" f"> MarsFormat openmars_file.nc -gcm openmars -bd\n" f"{Blue}(Creates openmars_file_daily.nc; 5-sol bin){Green}\n" @@ -178,17 +179,22 @@ def main(): print(f"{Yellow}***Notice*** No operation requested. Use '-gcm' and specify openmars, marswrf, pcm, emars") exit() # Exit cleanly + print(f"Running MarsFormat with args: {args}") + print(f"Current working directory: {os.getcwd()}") + print(f"Files in input_file: {[f.name for f in args.input_file]}") + print(f"File exists check: {all(os.path.exists(f.name) for f in args.input_file)}") + path2data = os.getcwd() # Load all of the netcdf files file_list = [f.name for f in args.input_file] model_type = args.gcm_name # e.g. 'legacy' for filei in file_list: - # Add path unless full path is provided - if '/' not in filei: - fullnameIN = path2data + '/' + filei - else: + # Use os.path.join for platform-independent path handling + if os.path.isabs(filei): fullnameIN = filei + else: + fullnameIN = os.path.join(path2data, filei) print('Processing...') # Load model variables, dimensions @@ -536,7 +542,8 @@ def main(): DS_average[model.dim_time].attrs['long_name'] = 'time averaged over %s sols'%(nday) # Create New File, set time dimension as unlimitted - fullnameOUT = fullnameIN[:-3]+ext+'.nc' + base_name = os.path.splitext(fullnameIN)[0] + fullnameOUT = f"{base_name}{ext}.nc" DS_average.to_netcdf(fullnameOUT,unlimited_dims=model.dim_time,format='NETCDF4_CLASSIC') diff --git a/bin/MarsInterp.py b/bin/MarsInterp.py index 5ceacd0d..b9314cf9 100755 --- a/bin/MarsInterp.py +++ b/bin/MarsInterp.py @@ -102,10 +102,12 @@ def wrapper(*args, **kwargs): parser.add_argument('-t', '--interp_type', type=str, default='pstd', help=( - f"Interpolation interp_: ``pstd``, ``zstd``, or ``zagl``.\n" + f"Interpolation to standard pressure (pstd), standard altitude " + f"(zstd), or altitude above ground level (zagl).\nWorks on " + f"'daily', 'average', and 'diurn' files.\n" f"{Green}Example:\n" f"> MarsInterp 01336.atmos_average.nc\n" - f"> MarsInterp 01336.atmos_average.nc -t pstd" + f"> MarsInterp 01336.atmos_average.nc -t pstd\n" f"{Nclr}\n\n" ) ) @@ -114,8 +116,11 @@ def wrapper(*args, **kwargs): parser.add_argument('-v', '--vertical_grid', type=str, default=None, help=( - f"Layer IDs as defined in ``amescap_profile``.\nFor first " + f"For use with ``-t``. Specify a custom vertical grid to " + f"interpolate to.\n" + f"Custom grids defined in ``amescap_profile``.\nFor first " f"time use, copy ``amescap_profile`` to your home directory:\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Cyan}cp path/to/amesCAP/mars_templates/amescap_profile " f"~/.amescap_profile\n" f"{Green}Example:\n" @@ -126,8 +131,9 @@ def wrapper(*args, **kwargs): parser.add_argument('-incl', '--include', nargs='+', help=( - f"Only include the listed variables. Dimensions and 1D " - f"variables are always included.\n" + f"Only include the listed variables in the action. Dimensions " + f"and 1D variables are always included.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsInterp 01336.atmos_daily.nc -incl temp ps ts" f"{Nclr}\n\n" @@ -153,8 +159,8 @@ def wrapper(*args, **kwargs): f"CAP to create a new file with the extension name specified " f"here.\n" f"{Green}Example:\n" - f"> MarsInterp 00334.atmos_average.nc -t pstd -ext _dflt_levs\n" - f"{Blue}(Produces 00334.atmos_average_dflt_levs.nc and " + f"> MarsInterp 00334.atmos_average.nc -t pstd -ext _my_pstd\n" + f"{Blue}(Produces 00334.atmos_average_my_pstd.nc and " f"preserves all other files)" f"{Nclr}\n\n" ) diff --git a/bin/MarsPlot.py b/bin/MarsPlot.py index 73f4787a..876fead2 100755 --- a/bin/MarsPlot.py +++ b/bin/MarsPlot.py @@ -134,6 +134,8 @@ def wrapper(*args, **kwargs): help=( f"Print the content of a netCDF file to the screen.\nVariables " f"are sorted by dimension.\n" + f"Works on ANY netCDF file, including 'daily', diurn', " + f"'average', and 'fixed'\n" f"{Green}Example:\n" f"> MarsPlot -i 01336.atmos_daily.nc" f"{Nclr}\n\n" @@ -164,9 +166,9 @@ def wrapper(*args, **kwargs): default=False, help=( f"Plot consecutive years of data over the same axes range (e.g." - f"Ls=0–360). For 1D time series plots.\nRequires ADD LINE " - f"in the Custom.in template (see template for instructions)." - f"\nDefault is to plot in monotonically increasing " + f"Ls=0–360). For 1D time series plots only.\nRequires ADD LINE " + f"in the Custom.in template (see template for instructions).\n" + f"Default action is to plot in monotonically increasing " f"format.\n" f"{Green}Example:\n" f"> MarsPlot Custom.in -sy" @@ -235,6 +237,7 @@ def wrapper(*args, **kwargs): help=( f"For use with ``-i --inspect``:\nPrint the values of the " f"specified variable to the screen.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsPlot -i 01336.atmos_daily.nc -values temp\n" f"{Blue}(quotes '' req. for browsing dimensions){Green}\n" @@ -248,6 +251,7 @@ def wrapper(*args, **kwargs): help=( f"For use with ``-i --inspect``:\nPrint the min, mean, and max " f"values of the specified variable to the screen.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsPlot -i 01336.atmos_daily.nc -stats temp\n" f"{Blue}(quotes '' req. for browsing dimensions){Green}\n" diff --git a/bin/MarsPull.py b/bin/MarsPull.py index 92d19fe4..7d16274d 100755 --- a/bin/MarsPull.py +++ b/bin/MarsPull.py @@ -216,7 +216,7 @@ def download(url, file_name): f.write(response.content) print(f"{fname} Done") -def file_list(list_of_files): +def print_file_list(list_of_files): print("Available files:") for file in list_of_files: print(file) @@ -269,8 +269,8 @@ def main(): fv3_files_available = re.findall(r'href="[^"]*\/([^"\/]+\.nc)"', fv3_dir_text) - file_list(legacy_files_available) - file_list(fv3_files_available) + print_file_list(legacy_files_available) + print_file_list(fv3_files_available) if args.directory_name: portal_dir=args.directory_name diff --git a/bin/MarsVars.py b/bin/MarsVars.py index 634b41f5..2c699562 100755 --- a/bin/MarsVars.py +++ b/bin/MarsVars.py @@ -314,8 +314,9 @@ def add_help(var_list): parser.add_argument('-add', '--add_variable', nargs='+', default=[], help=( - f"Add a new variable to file. Variables that can be added are " - f"listed below.\n" + f"Add a new variable to file. " + f"Works on 'daily', 'diurn', and 'average' files.\n" + f"Variables that can be added are listed below.\n" f"{Green}Example:\n" f"> MarsVars 01336.atmos_average.nc -add rho\n{Yellow}\n" f"{add_help(master_list)}\n" @@ -330,6 +331,7 @@ def add_help(var_list): default=[], help=( f"Differentiate a variable w.r.t. the Z axis.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"*Requires a variable with a vertical dimension*\n" f"A new variable ``d_dz_var`` in [Unit/m] will be added to the " f"file.\n" @@ -343,6 +345,7 @@ def add_help(var_list): parser.add_argument('-col', '--column_integrate', nargs='+', default=[], help=( f"Integrate a variable through the column.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"*Requires a variable with a vertical dimension*\n" f"A new variable (``var_col``) in [kg/m2] will be added to the " f"file.\n" @@ -356,6 +359,7 @@ def add_help(var_list): parser.add_argument('-zd', '--zonal_detrend', nargs='+', default=[], help=( f"Detrend a variable by substracting its zonal mean value.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"A new a variable (``var_p``) (for prime) will be added to the" f" file.\n" f"{Green}Example:\n" @@ -368,6 +372,7 @@ def add_help(var_list): parser.add_argument('-to_dz', '--dp_to_dz', nargs='+', default=[], help=( f"Convert aerosol opacity [op/Pa] to [op/m]. " + f"Works on 'daily', 'diurn', and 'average' files.\n" f"Requires ``DP`` & ``DZ`` to be present in the file already.\n" f"A new variable (``[variable]_dp_to_dz``) is added to the " f"file.\n" @@ -381,6 +386,7 @@ def add_help(var_list): parser.add_argument('-to_dp', '--dz_to_dp', nargs='+', default=[], help=( f"Convert aerosol opacity [op/m] to [op/Pa]. " + f"Works on 'daily', 'diurn', and 'average' files.\n" f"Requires ``DP`` & ``DZ`` to be present in the file already.\n" f"A new variable (``[variable]_dz_to_dp``) is added to the " f"file.\n" @@ -394,6 +400,7 @@ def add_help(var_list): parser.add_argument('-rm', '--remove_variable', nargs='+', default=[], help=( f"Remove a variable from a file.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsVars 01336.atmos_average.nc -rm ps" f"{Nclr}\n\n" @@ -404,6 +411,7 @@ def add_help(var_list): help=( f"Copy one or more variables from a file into a new file of " f"the same name with the appended extension: '_extract'.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsVars 01336.atmos_average.nc -extract ps temp\n" f"{Blue}(Creates 01336.atmos_average_extract.nc containing ps " @@ -416,11 +424,12 @@ def add_help(var_list): parser.add_argument('-edit', '--edit_variable', default=None, help=( f"Edit a variable's attributes or scale its values.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"Requires the use of one or more of the following flags:\n" f"``-rename``\n``-longname``\n``-unit``\n``-multiply``\n" f"{Green}Example:\n" f"> MarsVars 01336.atmos_average.nc -edit ps -rename ps_mbar " - f"-multiply 0.01 -longname 'Pressure scaled to mb' -unit 'mbar'" + f"-multiply 0.01 -longname 'Pressure in mb' -unit 'mbar'" f"{Nclr}\n\n" ) ) @@ -431,6 +440,7 @@ def add_help(var_list): parser.add_argument('-rename', '--rename', type=str, default=None, help=( f"Rename a variable. Requires ``-edit``.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsVars 01336.atmos_average.nc -edit ps -rename ps_mbar\n" f"{Nclr}\n\n" @@ -441,6 +451,7 @@ def add_help(var_list): parser.add_argument('-longname', '--longname', type=str, default=None, help=( f"Change a variable's 'longname' attribute. Requires ``-edit``.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsVars 01336.atmos_average.nc -edit ps -longname " f"'Pressure scaled to mb'" @@ -452,6 +463,7 @@ def add_help(var_list): parser.add_argument('-unit', '--unit', type=str, default=None, help=( f"Change a variable's unit text. Requires ``-edit``.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsVars 01336.atmos_average.nc -edit ps -unit 'mbar'" f"{Nclr}\n\n" @@ -462,6 +474,7 @@ def add_help(var_list): parser.add_argument('-multiply', '--multiply', type=float, default=None, help=( f"Scale a variable's values. Requires ``-edit``.\n" + f"Works on 'daily', 'diurn', and 'average' files.\n" f"{Green}Example:\n" f"> MarsVars 01336.atmos_average.nc -edit ps -multiply 0.01" f"{Nclr}\n\n" diff --git a/tests/test_marsformat.py b/tests/test_marsformat.py index 18a939cc..f8b42e66 100644 --- a/tests/test_marsformat.py +++ b/tests/test_marsformat.py @@ -21,9 +21,8 @@ class TestMarsFormat(unittest.TestCase): @classmethod def setUpClass(cls): """Set up the test environment""" - # Create a temporary directory for test files - cls.test_dir = os.path.join(os.path.expanduser('~'), 'MarsFormat_test') - os.makedirs(cls.test_dir, exist_ok=True) + # Create a temporary directory for test files instead of a fixed path + cls.test_dir = tempfile.mkdtemp(prefix='MarsFormat_test_') # Project root directory cls.project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -88,8 +87,23 @@ def run_mars_format(self, args): :param args: List of arguments to pass to MarsFormat :return: The subprocess result object """ + # Convert any relative file paths to absolute paths + abs_args = [] + for arg in args: + if arg.endswith('.nc'): + abs_args.append(os.path.join(self.test_dir, arg)) + else: + abs_args.append(arg) + # Construct the full command to run MarsFormat - cmd = [sys.executable, os.path.join(self.project_root, "bin", "MarsFormat.py")] + args + cmd = [sys.executable, os.path.join(self.project_root, "bin", "MarsFormat.py")] + abs_args + + # Print debugging info + print(f"Running command: {' '.join(cmd)}") + print(f"Working directory: {self.test_dir}") + print(f"File exists check: {os.path.exists(os.path.join(self.project_root, 'bin', 'MarsFormat.py'))}") + + # Run the command with extra verbosity # Run the command result = subprocess.run( @@ -100,6 +114,10 @@ def run_mars_format(self, args): env=dict(os.environ, PWD=self.test_dir) # Ensure current working directory is set ) + # Print both stdout and stderr to help debug + print(f"STDOUT: {result.stdout}") + print(f"STDERR: {result.stderr}") + return result def create_dummy_emars(self): @@ -546,8 +564,20 @@ def test_daily_average(self): # Check that the output file was created output_file = os.path.join(self.test_dir, "emars_test_daily.nc") - self.assertTrue(os.path.exists(output_file), f"Output file {output_file} was not created.") + alt_output_file = "emars_test_daily.nc" # Current directory + + # Check both locations + file_exists = os.path.exists(output_file) or os.path.exists(alt_output_file) + actual_file = output_file if os.path.exists(output_file) else alt_output_file if os.path.exists(alt_output_file) else None + + print(f"Checking for file at: {output_file}") + print(f"Alternative location: {alt_output_file}") + print(f"Current directory: {os.getcwd()}") + print(f"File exists: {file_exists}") + print(f"Actual file location: {actual_file}") + self.assertTrue(file_exists, f"Output file was not created in either location.") + # Open the output file and check that it contains the expected variables dataset = nc.Dataset(output_file, 'r')