diff --git a/.github/jobs/get_use_case_commands.py b/.github/jobs/get_use_case_commands.py
index 2324e8cd62..70381d135d 100755
--- a/.github/jobs/get_use_case_commands.py
+++ b/.github/jobs/get_use_case_commands.py
@@ -78,6 +78,7 @@ def handle_automation_env(host_name, reqs, work_dir):
f'cd {METPLUS_DOCKER_LOC};'
f'{work_dir}/manage_externals/checkout_externals'
f' -e {work_dir}/.github/parm/Externals_metdatadb.cfg;'
+ f'{python_path} -m pip install {METPLUS_DOCKER_LOC}/../METdatadb;'
'cd -;'
)
diff --git a/.github/jobs/run_diff_docker.py b/.github/jobs/run_diff_docker.py
index fee43a9d48..c6c3937434 100755
--- a/.github/jobs/run_diff_docker.py
+++ b/.github/jobs/run_diff_docker.py
@@ -80,7 +80,6 @@ def copy_to_diff_dir(file_path, data_type):
if not os.path.exists(output_dir):
os.makedirs(output_dir)
- print(f'Copying {file_path} to\n{output_path}')
try:
shutil.copyfile(file_path, output_path)
except OSError as err:
diff --git a/.github/parm/use_case_groups.json b/.github/parm/use_case_groups.json
index 125d2b9f44..ef1ae2ffec 100644
--- a/.github/parm/use_case_groups.json
+++ b/.github/parm/use_case_groups.json
@@ -121,7 +121,12 @@
},
{
"category": "s2s",
- "index_list": "6",
+ "index_list": "6-7",
+ "new": false
+ },
+ {
+ "category": "s2s",
+ "index_list": "8-9",
"new": false
},
{
diff --git a/ci/util/diff_util.py b/ci/util/diff_util.py
index c4fa7aa63d..e894bbda04 100644
--- a/ci/util/diff_util.py
+++ b/ci/util/diff_util.py
@@ -117,13 +117,14 @@ def compare_dir(dir_a, dir_b, debug=False, save_diff=False):
print(f"ERROR: File does not exist: {filepath_a}")
diff_files.append(('', filepath_b, 'file not found (new output)', ''))
- print("\nSummary:\n")
+ print("\n\n**************************************************\nSummary:\n")
if diff_files:
print("\nERROR: Some differences were found")
for filepath_a, filepath_b, reason, diff_file in diff_files:
print(f"{reason}\n A:{filepath_a}\n B:{filepath_b}")
if diff_file:
print(f"Difference file: {diff_file}")
+ print()
else:
print("\nNo differences found in any files")
diff --git a/docs/Contributors_Guide/coding_standards.rst b/docs/Contributors_Guide/coding_standards.rst
index 06cdfe4326..675880c0fe 100644
--- a/docs/Contributors_Guide/coding_standards.rst
+++ b/docs/Contributors_Guide/coding_standards.rst
@@ -13,3 +13,82 @@ Coding Standards
docstrings `_, and
`Sphinx `_ for documentation
* **NOTE: Please do not use f-strings in the run_metplus.py file so that the Python version check can notify the user of the incorrect version. Using Python 3.5 or earlier will output the SyntaxError from the f-string instead of the useful error message.**
+
+Python code analysis tools
+--------------------------
+
+Static:
+
+pylint
+^^^^^^
+
+::
+ pip install pylint or conda install pylint
+
+ pylint.org
+
+ checks for code errors
+
+ pylint pep8 code-to-analyze will check for errors as well as PEP-8 style code
+
+pyflakes
+^^^^^^^^
+
+::
+
+ pip install pyflakes or conda install pyflakes
+
+ parses code rather than importing code, therefore OK to use on modules with side-effects
+
+ checks for code errors
+
+ faster than pylint
+
+ https://pypi.python.org/pypi/pyflakes
+
+ flake8 is wrapper to pyflakes, performs PEP-8 style checking in addition to error checking
+ http://flake8.pycqa.org/en/latest/index.html#quickstart
+
+vulture
+^^^^^^^
+
+::
+
+ checks for unused imports, variables, methods, classed ie "dead code"
+
+ pip install vulture or conda install vulture
+
+ https://pypi.python.org/pypi/vulture
+
+Dynamic (run-time):
+
+
+cpde-coverage analysis
+^^^^^^^^^^^^^^^^^^^^^^
+
+Useful when running unit tests to determine whether tests are executing all possible branches, loops, etc.
+
+figleaf
+^^^^^^^
+
+http://darcs.idyll.org/~t/projects/figleaf/doc/
+Checking for God objects and God methods:
+
+(from Chapter 4 of "How to Make Mistakes in Python", Mike Pirnat)
+
+::
+
+ find . -name "*.py" -exec wc -l {} \; | sort -g -r
+ for all Python source files, order by size
+ anything over 1000 lines is worth investigating (as general rule of thumb)
+
+ grep "^class " mybigmodule.py |wc -l
+ counts the number of classes defined in mybigmodule.py
+
+ grep "\sdef " mybigmodule.py |wc -l
+
+ counts the number of methods defined within a class or other function (ie at some level of indentation) in mybigmodule.py
+
+ try this if the above doesn't work: grep "def " mybigmodule.py |wc -l
+
+ A high ratio of methods to classes warrants investigation (what constitutes a high ratio- 10:1, 5:1???)
diff --git a/docs/Contributors_Guide/github_workflow.rst b/docs/Contributors_Guide/github_workflow.rst
index d9f3fb839e..a2c632aab2 100644
--- a/docs/Contributors_Guide/github_workflow.rst
+++ b/docs/Contributors_Guide/github_workflow.rst
@@ -12,6 +12,9 @@ that described in
where new or updated code is created on a 'feature' branch that is based on
the `NCAR/METplus GitHub 'develop' branch `_.
+From James McCreight (WRF-Hydro team) this is a good write-up on
+`best practices for collaboration on GitHub `_
+
The feature branch is named after the corresponding GitHub issue:
*feature__*
diff --git a/docs/Release_Guide/metplus_development.rst b/docs/Release_Guide/metplus_development.rst
index ef345fbc18..2bd5843439 100644
--- a/docs/Release_Guide/metplus_development.rst
+++ b/docs/Release_Guide/metplus_development.rst
@@ -14,6 +14,6 @@ Create a new vX.Y.Z-betaN or vX.Y.Z-rcN development release from the develop bra
.. include:: release_steps/merge_release_issue.rst
.. include:: release_steps/create_release_on_github.rst
.. include:: release_steps/metplus/create_release_extra.rst
+.. include:: release_steps/metplus/update_version_on_develop.rst
.. include:: release_steps/metplus/update_dtc_website.rst
.. include:: release_steps/finalize_release_on_github_development.rst
-.. include:: release_steps/metplus/update_version_on_develop.rst
diff --git a/docs/Release_Guide/metplus_official.rst b/docs/Release_Guide/metplus_official.rst
index 6032298019..bfdc4a4d53 100644
--- a/docs/Release_Guide/metplus_official.rst
+++ b/docs/Release_Guide/metplus_official.rst
@@ -9,11 +9,11 @@ Create a new vX.Y.Z official release from the develop branch.
.. include:: release_steps/clone_project_repository.rst
.. include:: release_steps/checkout_develop_branch.rst
.. include:: release_steps/create_release_feature_branch.rst
-.. include:: release_steps/metplus/update_version_official.rst
+.. include:: release_steps/metplus/update_release_date.rst
.. include:: release_steps/update_release_notes_official.rst
.. include:: release_steps/rotate_authorship.rst
.. include:: release_steps/merge_release_issue.rst
-.. include:: release_steps/create_release_branch.rst
+.. include:: release_steps/metplus/create_release_reference_branch.rst
.. include:: release_steps/metplus/update_release_content.rst
.. include:: release_steps/push_release_branch.rst
.. include:: release_steps/create_release_on_github.rst
@@ -22,3 +22,4 @@ Create a new vX.Y.Z official release from the develop branch.
.. include:: release_steps/finalize_release_on_github_official.rst
.. include:: release_steps/metplus/update_version_on_develop.rst
.. include:: release_steps/update_docs_official.rst
+.. include:: release_steps/metplus/update_web_server_data.rst
diff --git a/docs/Release_Guide/release_steps/merge_release_issue.rst b/docs/Release_Guide/release_steps/merge_release_issue.rst
index 2b30dcb36a..da554f4da3 100644
--- a/docs/Release_Guide/release_steps/merge_release_issue.rst
+++ b/docs/Release_Guide/release_steps/merge_release_issue.rst
@@ -1,4 +1,5 @@
Merge Release Issue
-------------------
-* After updating the version number and release notes on a release feature branch, submit a pull request to merge those changes back into the source branch.
+* After updating the release-specific content on a release feature branch,
+ submit a pull request to merge those changes back into the source branch.
diff --git a/docs/Release_Guide/release_steps/metplus/create_release_reference_branch.rst b/docs/Release_Guide/release_steps/metplus/create_release_reference_branch.rst
new file mode 100644
index 0000000000..94845f5361
--- /dev/null
+++ b/docs/Release_Guide/release_steps/metplus/create_release_reference_branch.rst
@@ -0,0 +1,37 @@
+Create Release Reference Branch
+-------------------------------
+
+* Create a branch from the develop branch for the reference branch for the
+ new official release and push it to GitHub. The branch name should match
+ the format main_vX.Y-ref where X.Y is the major/minor release number.
+
+.. parsed-literal::
+
+ cd |projectRepo|
+ git checkout develop
+ git pull
+ git checkout -b main_vX.Y-ref
+ git push -u origin main_vX.Y-ref
+
+Pushing this branch to GitHub should trigger the GitHub Actions automation
+that runs all of the use cases and creates Docker data volumes with the output
+data. These data will be used to verify that any bugfixes applied to the
+main_vX.Y branch does not break any of existing logic.
+
+Navigate to https://github.com/dtcenter/METplus/actions and verify that a
+*Testing* workflow was triggered on the *main_vX.Y-ref* branch.
+
+.. figure:: /Release_Guide/release_steps/metplus/metplus-automation-reference-data.png
+
+* Wait until the entire workflow has run successfully. The final job entitled
+ "Create Output Docker Data Volumes" should create Docker data volumes for
+ each use case category on DockerHub (dtcenter/metplus-data-dev). The names
+ of these volumes start with *output-*.
+
+* After the truth data volumes have been generated, create the main_vX.Y
+ branch off of the -ref branch.
+
+::
+
+ git checkout -b main_vX.Y
+ git push -u origin main_vX.Y
diff --git a/docs/Release_Guide/release_steps/metplus/metplus-automation-reference-data.png b/docs/Release_Guide/release_steps/metplus/metplus-automation-reference-data.png
new file mode 100644
index 0000000000..374ba02ced
Binary files /dev/null and b/docs/Release_Guide/release_steps/metplus/metplus-automation-reference-data.png differ
diff --git a/docs/Release_Guide/release_steps/metplus/update_release_content.rst b/docs/Release_Guide/release_steps/metplus/update_release_content.rst
index 6b732193a2..92ba48afda 100644
--- a/docs/Release_Guide/release_steps/metplus/update_release_content.rst
+++ b/docs/Release_Guide/release_steps/metplus/update_release_content.rst
@@ -4,15 +4,22 @@ Update Release Content
Update content that should go into the release version but remain unchanged
in the develop branch.
-**Update the version number in the quick search links:**
+Update the version number
+^^^^^^^^^^^^^^^^^^^^^^^^^
-* Open the docs/Users_Guide/quicksearch.rst file for editing.
-* Replace the word "develop" in all of the links with "vX.Y.Z",
- replacing the X.Y.Z with the version number.
- For example, replace "develop" with "v4.0.0".
-* Save and close the file.
+Remove **-dev** from the version number:
-**Update the version numbers in the manage externals files:**
+* As of METplus 4.0.0, we are naming releases with X.Y.Z format even if Z is 0.
+* As of METplus v4.0.0, the file containing the version number is located at
+ **metplus/VERSION** (in earlier releases, the file was located at
+ docs/version or doc/version).
+* In the develop branch, the version should match the upcoming release
+ with -dev added to the end like X.Y.Z-betaN-dev, i.e. 4.0.0-beta1-dev
+* Remove **-dev** from the version number so that it matches the release
+ you are creating.
+
+Update the version numbers in the manage externals files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
build_components/Externals_stable.cfg
diff --git a/docs/Release_Guide/release_steps/metplus/update_release_date.rst b/docs/Release_Guide/release_steps/metplus/update_release_date.rst
new file mode 100644
index 0000000000..f2a1444fcd
--- /dev/null
+++ b/docs/Release_Guide/release_steps/metplus/update_release_date.rst
@@ -0,0 +1,5 @@
+Update Release Date
+^^^^^^^^^^^^^^^^^^^
+
+* The release date is stored in *metplus/RELEASE_DATE* in YYYYMMDD format.
+* Change the value stored in this file to match the current date.
\ No newline at end of file
diff --git a/docs/Release_Guide/release_steps/metplus/update_version_official.rst b/docs/Release_Guide/release_steps/metplus/update_version_official.rst
deleted file mode 100644
index b0f9d0e62a..0000000000
--- a/docs/Release_Guide/release_steps/metplus/update_version_official.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Update Version Number for Release
----------------------------------
-
-Remove **-dev** from the version number:
-
-* As of METplus 4.0.0, we are naming releases with X.Y.Z format even if Z is 0.
-* As of METplus v4.0.0, the file containing the version number is located at **metplus/VERSION** (in earlier releases, the file was located at docs/version or doc/version).
-* In the develop branch, the version should match the upcoming release with -dev added to the end like X.Y.Z-betaN-dev, i.e. 4.0.0-beta1-dev
-* Remove **-dev** from the version number so that it matches the release you are creating.
diff --git a/docs/Release_Guide/release_steps/metplus/update_version_on_develop.rst b/docs/Release_Guide/release_steps/metplus/update_version_on_develop.rst
index 8a71254a13..cbad49ae5c 100644
--- a/docs/Release_Guide/release_steps/metplus/update_version_on_develop.rst
+++ b/docs/Release_Guide/release_steps/metplus/update_version_on_develop.rst
@@ -1,9 +1,9 @@
Update Version on Develop Branch
--------------------------------
-Change metplus/VERSION value to the next release after this one with -dev added
-to the end. Releases will loosely following these names, but are subject to
-change:
+Switch to the develop branch and change metplus/VERSION value to the
+next release after this one with -dev added to the end.
+Releases will loosely following these names, but are subject to change:
+-------------------+-----------------------+
| Release Version | New Develop Version |
diff --git a/docs/Release_Guide/release_steps/metplus/update_web_server_data.rst b/docs/Release_Guide/release_steps/metplus/update_web_server_data.rst
new file mode 100644
index 0000000000..2e8311eb44
--- /dev/null
+++ b/docs/Release_Guide/release_steps/metplus/update_web_server_data.rst
@@ -0,0 +1,11 @@
+Update DTC Web Server Data
+--------------------------
+
+Create Directory for Next Release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+On the DTC web server where the sample input data for use cases is hosted,
+run the setup_next_release_data.py script for the next upcoming release
+to set up the data directory for the next major/minor version development.
+The script can be found in the METplus repository in internal_tests/use_cases.
+See the comments in the script for more details.
diff --git a/docs/Users_Guide/glossary.rst b/docs/Users_Guide/glossary.rst
index e69a9242ea..612d99e2c0 100644
--- a/docs/Users_Guide/glossary.rst
+++ b/docs/Users_Guide/glossary.rst
@@ -495,7 +495,10 @@ METplus Configuration Glossary
.. warning:: **DEPRECATED:** Please use :term:`PY_EMBED_INGEST__OUTPUT_DIR`.
ASCII2NC_CONFIG_FILE
- Path to optional configuration file read by ASCII2NC.
+ Path to optional configuration file read by ascii2nc.
+ To utilize a configuration file, set this to
+ {PARM_BASE}/parm/met_config/Ascii2NcConfig_wrapped.
+ If unset, no config file will be used.
| *Used by:* ASCII2NC
@@ -505,12 +508,14 @@ METplus Configuration Glossary
| *Used by:* ASCII2NC
TC_STAT_CONFIG_FILE
- Path to optional configuration file read by TCStat.
+ Path to configuration file read by tc_stat.
+ If unset, parm/met_config/TCStatConfig_wrapped will be used.
| *Used by:* TCStat
TC_RMW_CONFIG_FILE
- Path to optional configuration file read by TCRMW.
+ Path to configuration file read by tc_rmw.
+ If unset, parm/met_config/TCRMWConfig_wrapped will be used.
| *Used by:* TCRMW
@@ -788,7 +793,7 @@ METplus Configuration Glossary
| *Used by:* EnsembleStat, GridStat, MODE, StatAnalysis
CONFIG_FILE
- Specific configuration file name to use for MET tools.
+ .. warning:: **DEPRECATED:** Please use :term:`TCMPR_PLOTTER_CONFIG_FILE`.
| *Used by:* TCMPRPlotter
@@ -968,7 +973,8 @@ METplus Configuration Glossary
.. warning:: **DEPRECATED:** Please use :term:`ENSEMBLE_STAT_CONFIG_FILE` instead.
ENSEMBLE_STAT_CONFIG_FILE
- Specify the absolute path to the configuration file for the MET ensemble_stat tool.
+ Path to configuration file read by ensemble_stat.
+ If unset, parm/met_config/EnsembleStatConfig_wrapped will be used.
| *Used by:* EnsembleStat
@@ -1961,7 +1967,8 @@ METplus Configuration Glossary
.. warning:: **DEPRECATED:** Please use :term:`GRID_STAT_CONFIG_FILE` instead.
GRID_STAT_CONFIG_FILE
- Specify the absolute path to the configuration file used by the MET grid_stat tool.
+ Path to configuration file read by grid_stat.
+ If unset, parm/met_config/GridStatConfig_wrapped will be used.
| *Used by:* GridStat
@@ -2407,7 +2414,8 @@ METplus Configuration Glossary
.. warning:: **DEPRECATED:** Please use :term:`MODE_CONFIG_FILE` instead. Path to mode configuration file.
MODE_CONFIG_FILE
- Path to mode configuration file.
+ Path to configuration file read by mode.
+ If unset, parm/met_config/MODEConfig_wrapped will be used.
| *Used by:* MODE
@@ -2495,7 +2503,8 @@ METplus Configuration Glossary
.. warning:: **DEPRECATED:** Please use :term:`MTD_CONFIG_FILE` instead.
MTD_CONFIG_FILE
- Path to mode-TD configuration file.
+ Path to configuration file read by mtd.
+ If unset, parm/met_config/MTDConfig_wrapped will be used.
| *Used by:* MTD
@@ -3198,7 +3207,8 @@ METplus Configuration Glossary
| *Used by:* All
PB2NC_CONFIG_FILE
- Specify the absolute path to the configuration file for the MET pb2nc tool.
+ Path to configuration file read by pb2nc.
+ If unset, parm/met_config/PB2NCConfig_wrapped will be used.
| *Used by:* PB2NC
@@ -3367,7 +3377,8 @@ METplus Configuration Glossary
| *Used by:* TCMPRPlotter
POINT_STAT_CONFIG_FILE
- Specify the absolute path to the configuration file to be used with the MET point_stat tool.
+ Path to configuration file read by point_stat.
+ If unset, parm/met_config/PointStatConfig_wrapped will be used.
| *Used by:* PointStat
@@ -3549,7 +3560,8 @@ METplus Configuration Glossary
| *Used by:* TCMPRPlotter
SERIES_ANALYSIS_CONFIG_FILE
- Specify the absolute path for the configuration file to use with the MET series_analysis tool by initialization time.
+ Path to configuration file read by series_analysis.
+ If unset, parm/met_config/SeriesAnalysisConfig_wrapped will be used.
| *Used by:* SeriesAnalysis
@@ -3670,7 +3682,10 @@ METplus Configuration Glossary
.. warning:: **DEPRECATED:** Please use :term:`STAT_ANALYSIS_CONFIG_FILE` instead.
STAT_ANALYSIS_CONFIG_FILE
- Specify the absolute path for the configuration file used with the MET stat_analysis tool. It is recommended to set this to {PARM_BASE}/use_cases/plotting/met_config/STATAnalysisConfig.
+ Path to optional configuration file read by stat_analysis.
+ To utilize a configuration file, set this to
+ {PARM_BASE}/parm/met_config/STATAnalysisConfig_wrapped.
+ If unset, no config file will be used.
| *Used by:* StatAnalysis
@@ -3787,7 +3802,8 @@ METplus Configuration Glossary
| *Used by:* TCPairs
TC_PAIRS_CONFIG_FILE
- Provide the absolute path to the configuration file for the MET tc_pairs tool.
+ Path to configuration file read by tc_pairs.
+ If unset, parm/met_config/TCPairsConfig_wrapped will be used.
| *Used by:* TCPairs
@@ -4652,9 +4668,10 @@ METplus Configuration Glossary
| *Used by:* GridDiag
GRID_DIAG_CONFIG_FILE
- Specify the absolute path to the configuration file used by the MET grid_stat tool.
+ Path to configuration file read by grid_diag.
+ If unset, parm/met_config/GridDiagConfig_wrapped will be used.
- | *Used by:* GridStat
+ | *Used by:* GridDiag
GRID_DIAG_CUSTOM_LOOP_LIST
Sets custom string loop list for a specific wrapper. See :term:`CUSTOM_LOOP_LIST`.
@@ -4758,7 +4775,8 @@ METplus Configuration Glossary
| *Used by:* TCGen
TC_GEN_CONFIG_FILE
- Provide the absolute path to the configuration file for the MET TCGen tool.
+ Path to configuration file read by tc_gen.
+ If unset, parm/met_config/TCGenConfig_wrapped will be used.
| *Used by:* TCGen
diff --git a/internal_tests/pytests/ascii2nc/test_ascii2nc_wrapper.py b/internal_tests/pytests/ascii2nc/test_ascii2nc_wrapper.py
index e4e6fd00b5..641c4d3599 100644
--- a/internal_tests/pytests/ascii2nc/test_ascii2nc_wrapper.py
+++ b/internal_tests/pytests/ascii2nc/test_ascii2nc_wrapper.py
@@ -138,7 +138,7 @@ def test_ascii2nc_wrapper(metplus_config, config_overrides,
'use_cases/met_tool_wrapper/ASCII2NC/ASCII2NC.conf',
config_overrides)
)
- assert(wrapper.isOK)
+ assert wrapper.isOK
input_path = wrapper.config.getraw('config', 'ASCII2NC_INPUT_TEMPLATE')
input_dir = os.path.dirname(input_path)
@@ -157,10 +157,10 @@ def test_ascii2nc_wrapper(metplus_config, config_overrides,
config_file = wrapper.c_dict.get('CONFIG_FILE')
expected_cmd = (f"{app_path} "
- f"{input_dir}/{input_file} "
- f"{output_dir}/{output_file} "
- f"-config {config_file} "
- f"{verbosity}")
+ f"{input_dir}/{input_file} "
+ f"{output_dir}/{output_file} "
+ f"-config {config_file} "
+ f"{verbosity}")
assert(all_commands[0][0] == expected_cmd)
@@ -172,3 +172,15 @@ def test_ascii2nc_wrapper(metplus_config, config_overrides,
value = match.split('=', 1)[1]
assert (env_var_values.get(env_var_key, '') == value)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+ config = metplus_config()
+ config.set('config', 'INPUT_MUST_EXIST', False)
+
+ wrapper = ASCII2NCWrapper(config)
+ assert not wrapper.c_dict['CONFIG_FILE']
+
+ config.set('config', 'ASCII2NC_CONFIG_FILE', fake_config_name)
+ wrapper = ASCII2NCWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/ensemble_stat/test_ensemble_stat_wrapper.py b/internal_tests/pytests/ensemble_stat/test_ensemble_stat_wrapper.py
index b1bfa40b25..85517687f1 100644
--- a/internal_tests/pytests/ensemble_stat/test_ensemble_stat_wrapper.py
+++ b/internal_tests/pytests/ensemble_stat/test_ensemble_stat_wrapper.py
@@ -104,7 +104,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
config.set('config', key, value)
wrapper = EnsembleStatWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
all_cmds = wrapper.run_all_times()
for (_, actual_env_vars), run_time in zip(all_cmds, run_times):
@@ -376,8 +376,8 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
'["/some/climo_mean/file.txt"];}'),
'CLIMO_MEAN_FILE': '"/some/climo_mean/file.txt"'}),
- ({'ENSEMBLE_STAT_CLIMO_MEAN_FIELD': 'CLM_NAME', },
- {'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {field = ["CLM_NAME"];}'}),
+ ({'ENSEMBLE_STAT_CLIMO_MEAN_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}', },
+ {'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {field = [{name="CLM_NAME"; level="(0,0,*,*)";}];}'}),
({'ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD': 'NEAREST', },
{'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {regrid = {method = NEAREST;}}'}),
@@ -407,7 +407,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
({
'ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME': '/some/climo_mean/file.txt',
- 'ENSEMBLE_STAT_CLIMO_MEAN_FIELD': 'CLM_NAME',
+ 'ENSEMBLE_STAT_CLIMO_MEAN_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}',
'ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD': 'NEAREST',
'ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH': '1',
'ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH': '0.5',
@@ -419,7 +419,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
},
{'METPLUS_CLIMO_MEAN_DICT': ('climo_mean = {file_name = '
'["/some/climo_mean/file.txt"];'
- 'field = ["CLM_NAME"];'
+ 'field = [{name="CLM_NAME"; level="(0,0,*,*)";}];'
'regrid = {method = NEAREST;width = 1;'
'vld_thresh = 0.5;shape = SQUARE;}'
'time_interp_method = NEAREST;'
@@ -433,8 +433,8 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
'["/some/climo_stdev/file.txt"];}'),
'CLIMO_STDEV_FILE': '"/some/climo_stdev/file.txt"'}),
- ({'ENSEMBLE_STAT_CLIMO_STDEV_FIELD': 'CLM_NAME', },
- {'METPLUS_CLIMO_STDEV_DICT': 'climo_stdev = {field = ["CLM_NAME"];}'}),
+ ({'ENSEMBLE_STAT_CLIMO_STDEV_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}', },
+ {'METPLUS_CLIMO_STDEV_DICT': 'climo_stdev = {field = [{name="CLM_NAME"; level="(0,0,*,*)";}];}'}),
({'ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD': 'NEAREST', },
{
@@ -466,7 +466,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
({
'ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME': '/some/climo_stdev/file.txt',
- 'ENSEMBLE_STAT_CLIMO_STDEV_FIELD': 'CLM_NAME',
+ 'ENSEMBLE_STAT_CLIMO_STDEV_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}',
'ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD': 'NEAREST',
'ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH': '1',
'ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH': '0.5',
@@ -478,7 +478,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
},
{'METPLUS_CLIMO_STDEV_DICT': ('climo_stdev = {file_name = '
'["/some/climo_stdev/file.txt"];'
- 'field = ["CLM_NAME"];'
+ 'field = [{name="CLM_NAME"; level="(0,0,*,*)";}];'
'regrid = {method = NEAREST;width = 1;'
'vld_thresh = 0.5;shape = SQUARE;}'
'time_interp_method = NEAREST;'
@@ -499,7 +499,7 @@ def test_ensemble_stat_single_field(metplus_config, config_overrides,
config.set('config', key, value)
wrapper = EnsembleStatWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
app_path = os.path.join(config.getdir('MET_BIN_DIR'), wrapper.app_name)
verbosity = f"-v {wrapper.c_dict['VERBOSITY']}"
@@ -537,3 +537,18 @@ def test_ensemble_stat_single_field(metplus_config, config_overrides,
assert (actual_value == ens_fmt)
else:
assert(env_var_values.get(env_var_key, '') == actual_value)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'EnsembleStatConfig_wrapped')
+
+ wrapper = EnsembleStatWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'ENSEMBLE_STAT_CONFIG_FILE', fake_config_name)
+ wrapper = EnsembleStatWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/grid_diag/test_grid_diag.py b/internal_tests/pytests/grid_diag/test_grid_diag.py
index 05202292aa..21e48d27f4 100644
--- a/internal_tests/pytests/grid_diag/test_grid_diag.py
+++ b/internal_tests/pytests/grid_diag/test_grid_diag.py
@@ -170,3 +170,18 @@ def test_get_all_files_and_subset(metplus_config, time_info, expected_subset):
def test_get_list_file_name(metplus_config, time_info, expected_filename):
wrapper = GridDiagWrapper(metplus_config())
assert(wrapper.get_list_file_name(time_info, 'input0') == expected_filename)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'GridDiagConfig_wrapped')
+
+ wrapper = GridDiagWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'GRID_DIAG_CONFIG_FILE', fake_config_name)
+ wrapper = GridDiagWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/grid_stat/test_grid_stat_wrapper.py b/internal_tests/pytests/grid_stat/test_grid_stat_wrapper.py
index 00420bdd55..6b220af88d 100644
--- a/internal_tests/pytests/grid_stat/test_grid_stat_wrapper.py
+++ b/internal_tests/pytests/grid_stat/test_grid_stat_wrapper.py
@@ -97,7 +97,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
config.set('config', key, value)
wrapper = GridStatWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
all_cmds = wrapper.run_all_times()
for (_, actual_env_vars), run_time in zip(all_cmds, run_times):
@@ -421,8 +421,8 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
'["/some/climo_mean/file.txt"];}'),
'CLIMO_MEAN_FILE': '"/some/climo_mean/file.txt"'}),
- ({'GRID_STAT_CLIMO_MEAN_FIELD': 'CLM_NAME', },
- {'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {field = ["CLM_NAME"];}'}),
+ ({'GRID_STAT_CLIMO_MEAN_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}', },
+ {'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {field = [{name="CLM_NAME"; level="(0,0,*,*)";}];}'}),
({'GRID_STAT_CLIMO_MEAN_REGRID_METHOD': 'NEAREST', },
{'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {regrid = {method = NEAREST;}}'}),
@@ -452,7 +452,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
({
'GRID_STAT_CLIMO_MEAN_FILE_NAME': '/some/climo_mean/file.txt',
- 'GRID_STAT_CLIMO_MEAN_FIELD': 'CLM_NAME',
+ 'GRID_STAT_CLIMO_MEAN_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}',
'GRID_STAT_CLIMO_MEAN_REGRID_METHOD': 'NEAREST',
'GRID_STAT_CLIMO_MEAN_REGRID_WIDTH': '1',
'GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH': '0.5',
@@ -464,7 +464,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
},
{'METPLUS_CLIMO_MEAN_DICT': ('climo_mean = {file_name = '
'["/some/climo_mean/file.txt"];'
- 'field = ["CLM_NAME"];'
+ 'field = [{name="CLM_NAME"; level="(0,0,*,*)";}];'
'regrid = {method = NEAREST;width = 1;'
'vld_thresh = 0.5;shape = SQUARE;}'
'time_interp_method = NEAREST;'
@@ -478,8 +478,8 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
'["/some/climo_stdev/file.txt"];}'),
'CLIMO_STDEV_FILE': '"/some/climo_stdev/file.txt"'}),
- ({'GRID_STAT_CLIMO_STDEV_FIELD': 'CLM_NAME', },
- {'METPLUS_CLIMO_STDEV_DICT': 'climo_stdev = {field = ["CLM_NAME"];}'}),
+ ({'GRID_STAT_CLIMO_STDEV_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}', },
+ {'METPLUS_CLIMO_STDEV_DICT': 'climo_stdev = {field = [{name="CLM_NAME"; level="(0,0,*,*)";}];}'}),
({'GRID_STAT_CLIMO_STDEV_REGRID_METHOD': 'NEAREST', },
{
@@ -511,7 +511,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
({
'GRID_STAT_CLIMO_STDEV_FILE_NAME': '/some/climo_stdev/file.txt',
- 'GRID_STAT_CLIMO_STDEV_FIELD': 'CLM_NAME',
+ 'GRID_STAT_CLIMO_STDEV_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}',
'GRID_STAT_CLIMO_STDEV_REGRID_METHOD': 'NEAREST',
'GRID_STAT_CLIMO_STDEV_REGRID_WIDTH': '1',
'GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH': '0.5',
@@ -523,7 +523,7 @@ def test_handle_climo_file_variables(metplus_config, config_overrides,
},
{'METPLUS_CLIMO_STDEV_DICT': ('climo_stdev = {file_name = '
'["/some/climo_stdev/file.txt"];'
- 'field = ["CLM_NAME"];'
+ 'field = [{name="CLM_NAME"; level="(0,0,*,*)";}];'
'regrid = {method = NEAREST;width = 1;'
'vld_thresh = 0.5;shape = SQUARE;}'
'time_interp_method = NEAREST;'
@@ -553,7 +553,7 @@ def test_grid_stat_single_field(metplus_config, config_overrides,
config.set('config', key, value)
wrapper = GridStatWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
app_path = os.path.join(config.getdir('MET_BIN_DIR'), wrapper.app_name)
verbosity = f"-v {wrapper.c_dict['VERBOSITY']}"
@@ -589,3 +589,18 @@ def test_grid_stat_single_field(metplus_config, config_overrides,
assert (actual_value == obs_fmt)
else:
assert(env_var_values.get(env_var_key, '') == actual_value)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'GridStatConfig_wrapped')
+
+ wrapper = GridStatWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'GRID_STAT_CONFIG_FILE', fake_config_name)
+ wrapper = GridStatWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/mode/test_mode_wrapper.py b/internal_tests/pytests/mode/test_mode_wrapper.py
index 787f427738..69a17f9146 100644
--- a/internal_tests/pytests/mode/test_mode_wrapper.py
+++ b/internal_tests/pytests/mode/test_mode_wrapper.py
@@ -315,7 +315,7 @@ def test_mode_single_field(metplus_config, config_overrides,
config.set('config', key, value)
wrapper = MODEWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
app_path = os.path.join(config.getdir('MET_BIN_DIR'), wrapper.app_name)
verbosity = f"-v {wrapper.c_dict['VERBOSITY']}"
@@ -433,8 +433,23 @@ def test_config_synonyms(metplus_config, config_name, env_var_name,
set_minimum_config_settings(config)
config.set('config', config_name, in_value)
wrapper = MODEWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
expected_output = f'{met_name} = {out_value};'
assert(wrapper.env_var_dict[env_var_name] == expected_output)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'MODEConfig_wrapped')
+
+ wrapper = MODEWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'MODE_CONFIG_FILE', fake_config_name)
+ wrapper = MODEWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/mtd/test_mtd_wrapper.py b/internal_tests/pytests/mtd/test_mtd_wrapper.py
index 065124f6ed..27cf14b611 100644
--- a/internal_tests/pytests/mtd/test_mtd_wrapper.py
+++ b/internal_tests/pytests/mtd/test_mtd_wrapper.py
@@ -188,7 +188,7 @@ def test_mtd_single(metplus_config):
mw.c_dict['SINGLE_DATA_SRC'] = 'FCST'
mw.c_dict['FCST_INPUT_DIR'] = fcst_dir
mw.c_dict['FCST_INPUT_TEMPLATE'] = "{init?fmt=%Y%m%d}/{init?fmt=%Y%m%d}_i{init?fmt=%H}_f{lead?fmt=%.3H}_HRRRTLE_PHPT.grb2"
- input_dict = {'init' : datetime.datetime.strptime("201705100300", '%Y%m%d%H%M') }
+ input_dict = {'init': datetime.datetime.strptime("201705100300", '%Y%m%d%H%M') }
mw.run_at_time(input_dict)
single_list_file = os.path.join(mw.config.getdir('STAGING_DIR'), 'file_lists', '20170510040000_mtd_single_APCP.txt')
@@ -203,3 +203,18 @@ def test_mtd_single(metplus_config):
single_list[1] == os.path.join(fcst_dir,'20170510', '20170510_i03_f002_HRRRTLE_PHPT.grb2') and
single_list[2] == os.path.join(fcst_dir,'20170510', '20170510_i03_f003_HRRRTLE_PHPT.grb2')
)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'MTDConfig_wrapped')
+
+ wrapper = MTDWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'MTD_CONFIG_FILE', fake_config_name)
+ wrapper = MTDWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/pb2nc/test_pb2nc_wrapper.py b/internal_tests/pytests/pb2nc/test_pb2nc_wrapper.py
index 923a63d290..f9c3ab8cc0 100644
--- a/internal_tests/pytests/pb2nc/test_pb2nc_wrapper.py
+++ b/internal_tests/pytests/pb2nc/test_pb2nc_wrapper.py
@@ -317,7 +317,7 @@ def test_pb2nc_all_fields(metplus_config, config_overrides,
config.set('config', key, value)
wrapper = PB2NCWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
app_path = os.path.join(config.getdir('MET_BIN_DIR'), wrapper.app_name)
verbosity = f"-v {wrapper.c_dict['VERBOSITY']}"
@@ -347,3 +347,18 @@ def test_pb2nc_all_fields(metplus_config, config_overrides,
assert(match is not None)
value = match.split('=', 1)[1]
assert(env_var_values.get(env_var_key, '') == value)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'PB2NCConfig_wrapped')
+
+ wrapper = PB2NCWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'PB2NC_CONFIG_FILE', fake_config_name)
+ wrapper = PB2NCWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/point_stat/test_point_stat_wrapper.py b/internal_tests/pytests/point_stat/test_point_stat_wrapper.py
index f783182362..d169410db0 100755
--- a/internal_tests/pytests/point_stat/test_point_stat_wrapper.py
+++ b/internal_tests/pytests/point_stat/test_point_stat_wrapper.py
@@ -46,7 +46,7 @@ def test_met_dictionary_in_var_options(metplus_config):
'interp = { type = [ { method = NEAREST; width = 1; } ] };')
wrapper = PointStatWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
all_cmds = wrapper.run_all_times()
@@ -290,8 +290,8 @@ def test_met_dictionary_in_var_options(metplus_config):
'["/some/climo_mean/file.txt"];}'),
'CLIMO_MEAN_FILE': '"/some/climo_mean/file.txt"'}),
- ({'POINT_STAT_CLIMO_MEAN_FIELD': 'CLM_NAME', },
- {'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {field = ["CLM_NAME"];}'}),
+ ({'POINT_STAT_CLIMO_MEAN_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}', },
+ {'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {field = [{name="CLM_NAME"; level="(0,0,*,*)";}];}'}),
({'POINT_STAT_CLIMO_MEAN_REGRID_METHOD': 'NEAREST', },
{
@@ -323,7 +323,7 @@ def test_met_dictionary_in_var_options(metplus_config):
({
'POINT_STAT_CLIMO_MEAN_FILE_NAME': '/some/climo_mean/file.txt',
- 'POINT_STAT_CLIMO_MEAN_FIELD': 'CLM_NAME',
+ 'POINT_STAT_CLIMO_MEAN_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}',
'POINT_STAT_CLIMO_MEAN_REGRID_METHOD': 'NEAREST',
'POINT_STAT_CLIMO_MEAN_REGRID_WIDTH': '1',
'POINT_STAT_CLIMO_MEAN_REGRID_VLD_THRESH': '0.5',
@@ -335,7 +335,7 @@ def test_met_dictionary_in_var_options(metplus_config):
},
{'METPLUS_CLIMO_MEAN_DICT': ('climo_mean = {file_name = '
'["/some/climo_mean/file.txt"];'
- 'field = ["CLM_NAME"];'
+ 'field = [{name="CLM_NAME"; level="(0,0,*,*)";}];'
'regrid = {method = NEAREST;width = 1;'
'vld_thresh = 0.5;shape = SQUARE;}'
'time_interp_method = NEAREST;'
@@ -349,9 +349,9 @@ def test_met_dictionary_in_var_options(metplus_config):
'["/some/climo_stdev/file.txt"];}'),
'CLIMO_STDEV_FILE': '"/some/climo_stdev/file.txt"'}),
- ({'POINT_STAT_CLIMO_STDEV_FIELD': 'CLM_NAME', },
+ ({'POINT_STAT_CLIMO_STDEV_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}', },
{
- 'METPLUS_CLIMO_STDEV_DICT': 'climo_stdev = {field = ["CLM_NAME"];}'}),
+ 'METPLUS_CLIMO_STDEV_DICT': 'climo_stdev = {field = [{name="CLM_NAME"; level="(0,0,*,*)";}];}'}),
({'POINT_STAT_CLIMO_STDEV_REGRID_METHOD': 'NEAREST', },
{
@@ -384,7 +384,7 @@ def test_met_dictionary_in_var_options(metplus_config):
({
'POINT_STAT_CLIMO_STDEV_FILE_NAME': '/some/climo_stdev/file.txt',
- 'POINT_STAT_CLIMO_STDEV_FIELD': 'CLM_NAME',
+ 'POINT_STAT_CLIMO_STDEV_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}',
'POINT_STAT_CLIMO_STDEV_REGRID_METHOD': 'NEAREST',
'POINT_STAT_CLIMO_STDEV_REGRID_WIDTH': '1',
'POINT_STAT_CLIMO_STDEV_REGRID_VLD_THRESH': '0.5',
@@ -396,7 +396,7 @@ def test_met_dictionary_in_var_options(metplus_config):
},
{'METPLUS_CLIMO_STDEV_DICT': ('climo_stdev = {file_name = '
'["/some/climo_stdev/file.txt"];'
- 'field = ["CLM_NAME"];'
+ 'field = [{name="CLM_NAME"; level="(0,0,*,*)";}];'
'regrid = {method = NEAREST;width = 1;'
'vld_thresh = 0.5;shape = SQUARE;}'
'time_interp_method = NEAREST;'
@@ -469,7 +469,7 @@ def test_point_stat_all_fields(metplus_config, config_overrides,
config.set('config', key, value)
wrapper = PointStatWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
app_path = os.path.join(config.getdir('MET_BIN_DIR'), wrapper.app_name)
verbosity = f"-v {wrapper.c_dict['VERBOSITY']}"
@@ -507,3 +507,18 @@ def test_point_stat_all_fields(metplus_config, config_overrides,
assert (value == obs_fmt)
else:
assert(env_var_values.get(env_var_key, '') == value)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'PointStatConfig_wrapped')
+
+ wrapper = PointStatWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'POINT_STAT_CONFIG_FILE', fake_config_name)
+ wrapper = PointStatWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/series_analysis/test_series_analysis.py b/internal_tests/pytests/series_analysis/test_series_analysis.py
index bcdf600670..aead971ac1 100644
--- a/internal_tests/pytests/series_analysis/test_series_analysis.py
+++ b/internal_tests/pytests/series_analysis/test_series_analysis.py
@@ -95,8 +95,8 @@ def set_minimum_config_settings(config):
'["/some/climo_mean/file.txt"];}'),
'CLIMO_MEAN_FILE': '"/some/climo_mean/file.txt"'}),
- ({'SERIES_ANALYSIS_CLIMO_MEAN_FIELD': 'CLM_NAME', },
- {'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {field = ["CLM_NAME"];}'}),
+ ({'SERIES_ANALYSIS_CLIMO_MEAN_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}', },
+ {'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {field = [{name="CLM_NAME"; level="(0,0,*,*)";}];}'}),
({'SERIES_ANALYSIS_CLIMO_MEAN_REGRID_METHOD': 'NEAREST', },
{'METPLUS_CLIMO_MEAN_DICT': 'climo_mean = {regrid = {method = NEAREST;}}'}),
@@ -126,7 +126,7 @@ def set_minimum_config_settings(config):
({
'SERIES_ANALYSIS_CLIMO_MEAN_FILE_NAME': '/some/climo_mean/file.txt',
- 'SERIES_ANALYSIS_CLIMO_MEAN_FIELD': 'CLM_NAME',
+ 'SERIES_ANALYSIS_CLIMO_MEAN_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}',
'SERIES_ANALYSIS_CLIMO_MEAN_REGRID_METHOD': 'NEAREST',
'SERIES_ANALYSIS_CLIMO_MEAN_REGRID_WIDTH': '1',
'SERIES_ANALYSIS_CLIMO_MEAN_REGRID_VLD_THRESH': '0.5',
@@ -138,7 +138,7 @@ def set_minimum_config_settings(config):
},
{'METPLUS_CLIMO_MEAN_DICT': ('climo_mean = {file_name = '
'["/some/climo_mean/file.txt"];'
- 'field = ["CLM_NAME"];'
+ 'field = [{name="CLM_NAME"; level="(0,0,*,*)";}];'
'regrid = {method = NEAREST;width = 1;'
'vld_thresh = 0.5;shape = SQUARE;}'
'time_interp_method = NEAREST;'
@@ -152,8 +152,8 @@ def set_minimum_config_settings(config):
'["/some/climo_stdev/file.txt"];}'),
'CLIMO_STDEV_FILE': '"/some/climo_stdev/file.txt"'}),
- ({'SERIES_ANALYSIS_CLIMO_STDEV_FIELD': 'CLM_NAME', },
- {'METPLUS_CLIMO_STDEV_DICT': 'climo_stdev = {field = ["CLM_NAME"];}'}),
+ ({'SERIES_ANALYSIS_CLIMO_STDEV_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}', },
+ {'METPLUS_CLIMO_STDEV_DICT': 'climo_stdev = {field = [{name="CLM_NAME"; level="(0,0,*,*)";}];}'}),
({'SERIES_ANALYSIS_CLIMO_STDEV_REGRID_METHOD': 'NEAREST', },
{
@@ -185,7 +185,7 @@ def set_minimum_config_settings(config):
({
'SERIES_ANALYSIS_CLIMO_STDEV_FILE_NAME': '/some/climo_stdev/file.txt',
- 'SERIES_ANALYSIS_CLIMO_STDEV_FIELD': 'CLM_NAME',
+ 'SERIES_ANALYSIS_CLIMO_STDEV_FIELD': '{name="CLM_NAME"; level="(0,0,*,*)";}',
'SERIES_ANALYSIS_CLIMO_STDEV_REGRID_METHOD': 'NEAREST',
'SERIES_ANALYSIS_CLIMO_STDEV_REGRID_WIDTH': '1',
'SERIES_ANALYSIS_CLIMO_STDEV_REGRID_VLD_THRESH': '0.5',
@@ -197,7 +197,7 @@ def set_minimum_config_settings(config):
},
{'METPLUS_CLIMO_STDEV_DICT': ('climo_stdev = {file_name = '
'["/some/climo_stdev/file.txt"];'
- 'field = ["CLM_NAME"];'
+ 'field = [{name="CLM_NAME"; level="(0,0,*,*)";}];'
'regrid = {method = NEAREST;width = 1;'
'vld_thresh = 0.5;shape = SQUARE;}'
'time_interp_method = NEAREST;'
@@ -219,7 +219,7 @@ def test_series_analysis_single_field(metplus_config, config_overrides,
config.set('config', key, value)
wrapper = SeriesAnalysisWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
app_path = os.path.join(config.getdir('MET_BIN_DIR'), wrapper.app_name)
verbosity = f"-v {wrapper.c_dict['VERBOSITY']}"
@@ -801,3 +801,18 @@ def test_get_netcdf_min_max(metplus_config):
min, max = wrapper.get_netcdf_min_max(filepath, variable_name)
assert(min == expected_min)
assert(max == expected_max)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'SeriesAnalysisConfig_wrapped')
+
+ wrapper = SeriesAnalysisWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'SERIES_ANALYSIS_CONFIG_FILE', fake_config_name)
+ wrapper = SeriesAnalysisWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/stat_analysis/test_stat_analysis.py b/internal_tests/pytests/stat_analysis/test_stat_analysis.py
index 46137e6e3c..2c567aeaa7 100644
--- a/internal_tests/pytests/stat_analysis/test_stat_analysis.py
+++ b/internal_tests/pytests/stat_analysis/test_stat_analysis.py
@@ -795,3 +795,15 @@ def test_get_level_list(metplus_config, data_type, config_list, expected_list):
saw = StatAnalysisWrapper(config)
assert(saw.get_level_list(data_type) == expected_list)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+ config = metplus_config()
+ config.set('config', 'INPUT_MUST_EXIST', False)
+
+ wrapper = StatAnalysisWrapper(config)
+ assert not wrapper.c_dict['CONFIG_FILE']
+
+ config.set('config', 'STAT_ANALYSIS_CONFIG_FILE', fake_config_name)
+ wrapper = StatAnalysisWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/tc_gen/test_tc_gen_wrapper.py b/internal_tests/pytests/tc_gen/test_tc_gen_wrapper.py
index 2be49ab1e8..9486c629b6 100644
--- a/internal_tests/pytests/tc_gen/test_tc_gen_wrapper.py
+++ b/internal_tests/pytests/tc_gen/test_tc_gen_wrapper.py
@@ -310,7 +310,7 @@ def test_tc_gen(metplus_config, config_overrides, env_var_values):
config.set('config', key, value)
wrapper = TCGenWrapper(config)
- assert(wrapper.isOK)
+ assert wrapper.isOK
app_path = os.path.join(config.getdir('MET_BIN_DIR'), wrapper.app_name)
verbosity = f"-v {wrapper.c_dict['VERBOSITY']}"
@@ -361,3 +361,18 @@ def test_tc_gen(metplus_config, config_overrides, env_var_values):
with open(track_path, 'r') as file_handle:
lines = file_handle.read().splitlines()
assert(len(lines) == expected_track_count)
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'TCGenConfig_wrapped')
+
+ wrapper = TCGenWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'TC_GEN_CONFIG_FILE', fake_config_name)
+ wrapper = TCGenWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/tc_pairs/test_tc_pairs_wrapper.py b/internal_tests/pytests/tc_pairs/test_tc_pairs_wrapper.py
index e662b1ee17..21c00850ed 100644
--- a/internal_tests/pytests/tc_pairs/test_tc_pairs_wrapper.py
+++ b/internal_tests/pytests/tc_pairs/test_tc_pairs_wrapper.py
@@ -68,7 +68,7 @@ def test_read_storm_info(metplus_config, config_overrides, isOK):
config.set('config', key, value)
wrapper = TCPairsWrapper(config)
- assert(wrapper.isOK == isOK)
+ assert wrapper.isOK == isOK
@pytest.mark.parametrize(
'storm_id,basin,cyclone', [
@@ -511,3 +511,20 @@ def test_tc_pairs_read_all_files(metplus_config, config_overrides,
# unset begin and end for next loop
del env_var_values[f'METPLUS_{loop_by}_BEG']
del env_var_values[f'METPLUS_{loop_by}_END']
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+ config.set('config', 'INIT_TIME_FMT', time_fmt)
+ config.set('config', 'INIT_BEG', run_times[0])
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'TCPairsConfig_wrapped')
+
+ wrapper = TCPairsWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'TC_PAIRS_CONFIG_FILE', fake_config_name)
+ wrapper = TCPairsWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/pytests/tc_stat/test_tc_stat_wrapper.py b/internal_tests/pytests/tc_stat/test_tc_stat_wrapper.py
index 34b88fb999..b464c2aa85 100644
--- a/internal_tests/pytests/tc_stat/test_tc_stat_wrapper.py
+++ b/internal_tests/pytests/tc_stat/test_tc_stat_wrapper.py
@@ -247,3 +247,20 @@ def test_handle_jobs_create_parent_dir(metplus_config, jobs, init_dt,
# remove parent dirs to clean up for next run
cleanup_test_dirs(parent_dirs, output_dir)
+
+
+def test_get_config_file(metplus_config):
+ fake_config_name = '/my/config/file'
+
+ config = metplus_config()
+
+ default_config_file = os.path.join(config.getdir('PARM_BASE'),
+ 'met_config',
+ 'TCStatConfig_wrapped')
+
+ wrapper = TCStatWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == default_config_file
+
+ config.set('config', 'TC_STAT_CONFIG_FILE', fake_config_name)
+ wrapper = TCStatWrapper(config)
+ assert wrapper.c_dict['CONFIG_FILE'] == fake_config_name
diff --git a/internal_tests/use_cases/all_use_cases.txt b/internal_tests/use_cases/all_use_cases.txt
index 5c5c8df264..e8242d6623 100644
--- a/internal_tests/use_cases/all_use_cases.txt
+++ b/internal_tests/use_cases/all_use_cases.txt
@@ -121,7 +121,9 @@ Category: s2s
4::TCGen_fcstGFSO_obsBDECKS_GDF_TDF:: model_applications/s2s/TCGen_fcstGFSO_obsBDECKS_GDF_TDF.conf:: metplotpy_env,metplus
5::UserScript_obsPrecip_obsOnly_Hovmoeller:: model_applications/s2s/UserScript_obsPrecip_obsOnly_Hovmoeller.conf:: metplotpy_env
6:: UserScript_obsPrecip_obsOnly_CrossSpectraPlot:: model_applications/s2s/UserScript_obsPrecip_obsOnly_CrossSpectraPlot.conf:: spacetime_env
-7:: UserScript_fcstGFS_obsERA_OMI:: model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf:: spacetime_env
+7:: UserScript_fcstGFS_obsERA_PhaseDiagram:: model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.conf:: spacetime_env
+8:: UserScript_fcstGFS_obsERA_OMI:: model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf:: spacetime_env, metdatadb
+9:: UserScript_fcstGFS_obsERA_RMM:: model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf:: spacetime_env, metdatadb
Category: space_weather
diff --git a/internal_tests/use_cases/setup_next_release_data.py b/internal_tests/use_cases/setup_next_release_data.py
new file mode 100755
index 0000000000..f6f42e1a82
--- /dev/null
+++ b/internal_tests/use_cases/setup_next_release_data.py
@@ -0,0 +1,114 @@
+#! /usr/bin/env python3
+
+################################################################################
+# Name: setup_next_release_data.py
+# Author: George McCabe (mccabe@ucar.edu)
+# Description: Run this script from the DTC web server after cutting an
+# official release to set up the data directory for the next upcoming
+# release. For example, if 4.0.0 was just created, then run this script
+# with 4.1 as the argument. If 4.1.0 was just created, then run this
+# script with 5.0 as the argument unless it has been decided that we will
+# create a 4.2 release. The script will create a directory for the new
+# version and create symbolic links for each data set to point to the
+# version of that data set that was last updated. For example, if the
+# climate data set has not been updated since v3.1, then the symbolic link
+# will point into the v3.1 directory to that appropriate tar file.
+################################################################################
+
+import sys
+import os
+import re
+
+data_dir = '/home/met_test/METplus_Data'
+
+def get_files_from_dir(version_dir, check_dir):
+ files = os.listdir(check_dir)
+ if not files:
+ return False
+
+ print(f"Using {check_dir}")
+
+ found_files = False
+ for filename in files:
+ if not filename.startswith('sample_data'):
+ continue
+
+ filepath = os.path.join(check_dir, filename)
+ if os.path.islink(filepath):
+ print(f"\nFound symbolic link: {filepath}")
+ filepath = os.path.realpath(filepath)
+ filename = os.path.basename(filepath)
+ print(f"Real path: {filepath}")
+ elif os.path.isfile(filepath):
+ print(f"\nFound file: {filepath}")
+ else:
+ print(f"ERROR: Unexpected non-file found: {filepath}")
+ return False
+
+ linkname = f"{'-'.join(filename.split('-')[0:-1])}.tgz"
+ linkpath = os.path.join(version_dir, linkname)
+ print(f"Creating symbolic link:\n"
+ f" TO: {filepath}\n AT: {linkpath}")
+ os.symlink(filepath, linkpath)
+ found_files = True
+
+ return found_files
+
+def main(new_version):
+ match = re.match(r'^v([0-9]+)\.([0-9]+)', new_version)
+ if not match:
+ print(f"ERROR: Version does not match vX.Y format: {new_version}")
+ sys.exit(1)
+
+ major = int(match.group(1))
+ minor = int(match.group(2))
+
+ version = f'v{major}.{minor}'
+ print(f"Handling {version}")
+
+ version_dir = os.path.join(data_dir, version)
+
+ if not os.path.exists(version_dir):
+ print(f"Creating directory: {version_dir}")
+ os.makedirs(version_dir)
+
+ if os.listdir(version_dir):
+ print(f"ERROR: Directory is not empty: {version_dir}")
+ sys.exit(1)
+
+ # loop down versions, i.e. 4.0, 3.1, 3.0, 2.X, etc.
+ for cur_major in range(major, -1, -1):
+ # if looking at the major version
+ if cur_major == major:
+ # if minor is 0, skip to next major
+ if minor == 0:
+ continue
+ # otherwise start with 1 below minor version
+ minor_start = minor - 1
+ # if looking at lower than major, start minor
+ # with 5 in case minor > 1 is created
+ else:
+ minor_start = 5
+
+ for cur_minor in range(minor_start, -1, -1):
+ cur_version = f'v{cur_major}.{cur_minor}'
+ print(f"Looking for {cur_version}")
+ check_dir = os.path.join(data_dir, cur_version)
+ if os.path.exists(check_dir):
+ if get_files_from_dir(version_dir, check_dir):
+ print("\nSymbolic links created "
+ f"successfully in {version_dir}")
+ return True
+
+ return False
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print("ERROR: Must supply new major/minor version "
+ "as argument, i.e. v4.0")
+ sys.exit(1)
+
+ new_version = sys.argv[1]
+ if not main(new_version):
+ print("Something went wrong")
+ sys.exit(1)
diff --git a/metplus/wrappers/ascii2nc_wrapper.py b/metplus/wrappers/ascii2nc_wrapper.py
index fdb2a50b09..308a84ee5a 100755
--- a/metplus/wrappers/ascii2nc_wrapper.py
+++ b/metplus/wrappers/ascii2nc_wrapper.py
@@ -43,9 +43,11 @@ def create_c_dict(self):
'LOG_ASCII2NC_VERBOSITY',
c_dict['VERBOSITY'])
c_dict['ALLOW_MULTIPLE_FILES'] = True
- c_dict['CONFIG_FILE'] = self.config.getraw('config',
- 'ASCII2NC_CONFIG_FILE',
- '')
+
+ # ASCII2NC config file is optional, so
+ # don't provide wrapped config file name as default value
+ c_dict['CONFIG_FILE'] = self.get_config_file()
+
c_dict['ASCII_FORMAT'] = self.config.getstr('config',
'ASCII2NC_INPUT_FORMAT',
'')
diff --git a/metplus/wrappers/command_builder.py b/metplus/wrappers/command_builder.py
index b4827e9091..343333010c 100755
--- a/metplus/wrappers/command_builder.py
+++ b/metplus/wrappers/command_builder.py
@@ -145,6 +145,11 @@ def check_for_unused_env_vars(self):
if not hasattr(self, 'WRAPPER_ENV_VAR_KEYS'):
return
+ if not os.path.exists(config_file):
+ if self.c_dict.get('INPUT_MUST_EXIST', True):
+ self.log_error(f'Config file does not exist: {config_file}')
+ return
+
# read config file content
with open(config_file, 'r') as file_handle:
content = file_handle.read()
@@ -1425,24 +1430,28 @@ def set_met_config_list(self, c_dict, mp_config, met_config_name,
return
# convert value from config to a list
- conf_value = util.getlist(conf_value)
- if conf_value or kwargs.get('allow_empty', False):
- conf_value = str(conf_value)
- # if not removing quotes, escape any quotes found in list items
- if not kwargs.get('remove_quotes', False):
- conf_value = conf_value.replace('"', '\\"')
-
- conf_value = conf_value.replace("'", '"')
-
- if kwargs.get('remove_quotes', False):
- conf_value = conf_value.replace('"', '')
+ conf_values = util.getlist(conf_value)
+ if conf_values or kwargs.get('allow_empty', False):
+ out_values = []
+ for conf_value in conf_values:
+ remove_quotes = kwargs.get('remove_quotes', False)
+ # if not removing quotes, escape any quotes found in list items
+ if not remove_quotes:
+ conf_value = conf_value.replace('"', '\\"')
+
+ conf_value = util.remove_quotes(conf_value)
+ if not remove_quotes:
+ conf_value = f'"{conf_value}"'
+
+ out_values.append(conf_value)
+ out_value = f"[{', '.join(out_values)}]"
if not c_dict_key:
c_key = met_config_name.upper()
else:
c_key = c_dict_key
- conf_value = f'{met_config_name} = {conf_value};'
+ conf_value = f'{met_config_name} = {out_value};'
c_dict[c_key] = conf_value
def set_met_config_string(self, c_dict, mp_config, met_config_name,
@@ -1794,7 +1803,7 @@ def handle_climo_dict(self):
# define layout of climo_mean and climo_stdev dictionaries
climo_items = {
'file_name': ('list', '', None),
- 'field': ('list', '', None),
+ 'field': ('list', 'remove_quotes', None),
'regrid': ('dict', '', [
('method', 'string',
'uppercase,remove_quotes'),
@@ -2114,8 +2123,9 @@ def handle_time_summary_dict(self, c_dict, remove_bracket_list=None):
if not remove_bracket_list:
return
- for list_values in remove_bracket_list:
- c_dict[list_values] = c_dict[list_values].strip('[]')
+ for list_value in remove_bracket_list:
+ if c_dict.get(list_value):
+ c_dict[list_value] = c_dict[list_value].strip('[]')
def handle_mask(self, single_value=False, get_flags=False):
"""! Read mask dictionary values and set them into env_var_list
@@ -2278,6 +2288,29 @@ def get_met_config(self, **kwargs):
"""
return met_config(**kwargs)
+ def get_config_file(self, default_config_file=None):
+ """! Get the MET config file path for the wrapper from the
+ METplusConfig object. If unset, use the default value if provided.
+
+ @param default_config_file (optional) filename of wrapped MET config
+ file found in parm/met_config to use if config file is not set
+ @returns path to wrapped config file or None if no default is provided
+ """
+ config_name = f'{self.app_name.upper()}_CONFIG_FILE'
+ config_file = self.config.getraw('config', config_name, '')
+ if not config_file:
+ if not default_config_file:
+ return None
+
+ default_config_path = os.path.join(self.config.getdir('PARM_BASE'),
+ 'met_config',
+ default_config_file)
+ self.logger.debug(f"{config_name} is not set. "
+ f"Using {default_config_path}")
+ config_file = default_config_path
+
+ return config_file
+
def get_start_time_input_dict(self):
"""! Get the first run time specified in config. Used if only running
the wrapper once (LOOP_ORDER = processes).
diff --git a/metplus/wrappers/ensemble_stat_wrapper.py b/metplus/wrappers/ensemble_stat_wrapper.py
index 61a1964caa..5a4677fab1 100755
--- a/metplus/wrappers/ensemble_stat_wrapper.py
+++ b/metplus/wrappers/ensemble_stat_wrapper.py
@@ -204,13 +204,10 @@ def create_c_dict(self):
c_dict['OBS_GRID_FILE_WINDOW_BEGIN'] = c_dict['OBS_FILE_WINDOW_BEGIN']
c_dict['OBS_GRID_FILE_WINDOW_END'] = c_dict['OBS_FILE_WINDOW_END']
- # set the MET config file path and variables set
- # in th config file via environment variables
- c_dict['CONFIG_FILE'] = \
- self.config.getraw('config', 'ENSEMBLE_STAT_CONFIG_FILE', '')
-
- if not c_dict['CONFIG_FILE']:
- self.log_error("Must set ENSEMBLE_STAT_CONFIG_FILE.")
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = (
+ self.get_config_file('EnsembleStatConfig_wrapped')
+ )
# read by MET through environment variable, not set in MET config file
c_dict['MET_OBS_ERR_TABLE'] = \
diff --git a/metplus/wrappers/grid_diag_wrapper.py b/metplus/wrappers/grid_diag_wrapper.py
index a1fa89ac45..f68b0182d1 100755
--- a/metplus/wrappers/grid_diag_wrapper.py
+++ b/metplus/wrappers/grid_diag_wrapper.py
@@ -48,10 +48,9 @@ def create_c_dict(self):
'LOG_GRID_DIAG_VERBOSITY',
c_dict['VERBOSITY'])
c_dict['ALLOW_MULTIPLE_FILES'] = True
- c_dict['CONFIG_FILE'] = self.config.getraw('config',
- 'GRID_DIAG_CONFIG_FILE')
- if not c_dict['CONFIG_FILE']:
- self.log_error('GRID_DIAG_CONFIG_FILE required to run.')
+
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('GridDiagConfig_wrapped')
c_dict['INPUT_DIR'] = self.config.getdir('GRID_DIAG_INPUT_DIR', '')
self.get_input_templates(c_dict)
diff --git a/metplus/wrappers/grid_stat_wrapper.py b/metplus/wrappers/grid_stat_wrapper.py
index 10995682cf..33ca143376 100755
--- a/metplus/wrappers/grid_stat_wrapper.py
+++ b/metplus/wrappers/grid_stat_wrapper.py
@@ -104,8 +104,10 @@ def create_c_dict(self):
c_dict['VERBOSITY'] = self.config.getstr('config',
'LOG_GRID_STAT_VERBOSITY',
c_dict['VERBOSITY'])
- c_dict['CONFIG_FILE'] = self.config.getraw('config',
- 'GRID_STAT_CONFIG_FILE', '')
+
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('GridStatConfig_wrapped')
+
c_dict['OBS_INPUT_DIR'] = \
self.config.getdir('OBS_GRID_STAT_INPUT_DIR', '')
c_dict['OBS_INPUT_TEMPLATE'] = \
diff --git a/metplus/wrappers/mode_wrapper.py b/metplus/wrappers/mode_wrapper.py
index 346434abf0..5b126d7455 100755
--- a/metplus/wrappers/mode_wrapper.py
+++ b/metplus/wrappers/mode_wrapper.py
@@ -116,11 +116,9 @@ def create_c_dict(self):
c_dict['VERBOSITY'] = self.config.getstr('config',
'LOG_MODE_VERBOSITY',
c_dict['VERBOSITY'])
- c_dict['CONFIG_FILE'] = self.config.getraw('config',
- 'MODE_CONFIG_FILE',
- '')
- if not c_dict['CONFIG_FILE']:
- self.log_error('MODE_CONFIG_FILE must be set')
+
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('MODEConfig_wrapped')
c_dict['OBS_INPUT_DIR'] = \
self.config.getdir('OBS_MODE_INPUT_DIR', '')
diff --git a/metplus/wrappers/mtd_wrapper.py b/metplus/wrappers/mtd_wrapper.py
index be8adea1ee..30807f592a 100755
--- a/metplus/wrappers/mtd_wrapper.py
+++ b/metplus/wrappers/mtd_wrapper.py
@@ -62,9 +62,10 @@ def create_c_dict(self):
self.config.getraw('config',
'MTD_OUTPUT_TEMPLATE')
)
- c_dict['CONFIG_FILE'] = self.config.getraw('config',
- 'MTD_CONFIG_FILE',
- '')
+
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('MTDConfig_wrapped')
+
# new method of reading/setting MET config values
self.set_met_config_int(self.env_var_dict, 'MTD_MIN_VOLUME',
'min_volume', 'METPLUS_MIN_VOLUME')
diff --git a/metplus/wrappers/pb2nc_wrapper.py b/metplus/wrappers/pb2nc_wrapper.py
index c3c9f52853..8d656df648 100755
--- a/metplus/wrappers/pb2nc_wrapper.py
+++ b/metplus/wrappers/pb2nc_wrapper.py
@@ -88,12 +88,8 @@ def create_c_dict(self):
'PB2NC_INPUT_DATATYPE', '')
)
- # Configuration
- c_dict['CONFIG_FILE'] = self.config.getraw('config',
- 'PB2NC_CONFIG_FILE',
- '')
- if c_dict['CONFIG_FILE'] == '':
- self.log_error('PB2NC_CONFIG_FILE is required')
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('PB2NCConfig_wrapped')
self.set_met_config_list(self.env_var_dict,
'PB2NC_MESSAGE_TYPE',
diff --git a/metplus/wrappers/point_stat_wrapper.py b/metplus/wrappers/point_stat_wrapper.py
index 0c26a268eb..1183bdcec1 100755
--- a/metplus/wrappers/point_stat_wrapper.py
+++ b/metplus/wrappers/point_stat_wrapper.py
@@ -134,10 +134,8 @@ def create_c_dict(self):
# get climatology config variables
self.handle_climo_dict()
- # Configuration
- c_dict['CONFIG_FILE'] = (
- self.config.getraw('config', 'POINT_STAT_CONFIG_FILE', '')
- )
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('PointStatConfig_wrapped')
self.handle_obs_window_variables(c_dict)
@@ -232,9 +230,6 @@ def create_c_dict(self):
if not c_dict['OUTPUT_DIR']:
self.log_error('Must set POINT_STAT_OUTPUT_DIR in config file')
- if not c_dict['CONFIG_FILE']:
- self.log_error("POINT_STAT_CONFIG_FILE must be set.")
-
return c_dict
def add_obs_valid_args(self, time_info):
diff --git a/metplus/wrappers/series_analysis_wrapper.py b/metplus/wrappers/series_analysis_wrapper.py
index b05f055426..0367b7ad83 100755
--- a/metplus/wrappers/series_analysis_wrapper.py
+++ b/metplus/wrappers/series_analysis_wrapper.py
@@ -221,12 +221,10 @@ def create_c_dict(self):
if not c_dict['OUTPUT_DIR']:
self.log_error("Must set SERIES_ANALYSIS_OUTPUT_DIR to run.")
+ # get the MET config file path or use default
c_dict['CONFIG_FILE'] = (
- self.config.getraw('config',
- 'SERIES_ANALYSIS_CONFIG_FILE')
+ self.get_config_file('SeriesAnalysisConfig_wrapped')
)
- if not c_dict['CONFIG_FILE']:
- self.log_error("SERIES_ANALYSIS_CONFIG_FILE must be set")
c_dict['BACKGROUND_MAP'] = (
self.config.getbool('config',
diff --git a/metplus/wrappers/stat_analysis_wrapper.py b/metplus/wrappers/stat_analysis_wrapper.py
index e78d441bc6..0e6ad4f1e4 100755
--- a/metplus/wrappers/stat_analysis_wrapper.py
+++ b/metplus/wrappers/stat_analysis_wrapper.py
@@ -154,9 +154,10 @@ def create_c_dict(self):
c_dict['VERBOSITY'])
)
c_dict['LOOP_ORDER'] = self.config.getstr('config', 'LOOP_ORDER')
- c_dict['CONFIG_FILE'] = self.config.getstr('config',
- 'STAT_ANALYSIS_CONFIG_FILE',
- '')
+
+ # STATAnalysis config file is optional, so
+ # don't provide wrapped config file name as default value
+ c_dict['CONFIG_FILE'] = self.get_config_file()
c_dict['OUTPUT_DIR'] = self.config.getdir('STAT_ANALYSIS_OUTPUT_DIR',
'')
diff --git a/metplus/wrappers/tc_gen_wrapper.py b/metplus/wrappers/tc_gen_wrapper.py
index 3a8b61cbf8..6876731bfd 100755
--- a/metplus/wrappers/tc_gen_wrapper.py
+++ b/metplus/wrappers/tc_gen_wrapper.py
@@ -105,10 +105,9 @@ def create_c_dict(self):
c_dict['VERBOSITY'])
)
c_dict['ALLOW_MULTIPLE_FILES'] = True
- c_dict['CONFIG_FILE'] = (
- self.config.getraw('config',
- f'{app_name_upper}_CONFIG_FILE', '')
- )
+
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('TCGenConfig_wrapped')
c_dict['GENESIS_INPUT_DIR'] = (
self.config.getdir(f'{app_name_upper}_GENESIS_INPUT_DIR', '')
diff --git a/metplus/wrappers/tc_pairs_wrapper.py b/metplus/wrappers/tc_pairs_wrapper.py
index 91824b11c5..59a6fa1a13 100755
--- a/metplus/wrappers/tc_pairs_wrapper.py
+++ b/metplus/wrappers/tc_pairs_wrapper.py
@@ -96,12 +96,9 @@ def create_c_dict(self):
c_dict['MISSING_VAL'] = (
self.config.getstr('config', 'TC_PAIRS_MISSING_VAL', '-9999')
)
- c_dict['CONFIG_FILE'] = self.config.getraw('config',
- 'TC_PAIRS_CONFIG_FILE',
- '')
- if not c_dict['CONFIG_FILE']:
- self.log_error("TC_PAIRS_CONFIG_FILE is required to "
- "run TCPairs wrapper")
+
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('TCPairsConfig_wrapped')
self.add_met_config(name='init_beg',
data_type='string',
@@ -167,10 +164,14 @@ def create_c_dict(self):
self.config.getdir('TC_PAIRS_BDECK_INPUT_DIR', '')
c_dict['EDECK_DIR'] = \
self.config.getdir('TC_PAIRS_EDECK_INPUT_DIR', '')
- c_dict['OUTPUT_DIR'] = self.config.getdir('TC_PAIRS_OUTPUT_DIR')
+ c_dict['OUTPUT_DIR'] = self.config.getdir('TC_PAIRS_OUTPUT_DIR', '')
+ if not c_dict['OUTPUT_DIR']:
+ self.log_error('TC_PAIRS_OUTPUT_DIR must be set')
+
c_dict['READ_ALL_FILES'] = (
self.config.getbool('config',
- 'TC_PAIRS_READ_ALL_FILES')
+ 'TC_PAIRS_READ_ALL_FILES',
+ False)
)
# get list of models to process
diff --git a/metplus/wrappers/tc_stat_wrapper.py b/metplus/wrappers/tc_stat_wrapper.py
index f90574b761..513911c4b5 100755
--- a/metplus/wrappers/tc_stat_wrapper.py
+++ b/metplus/wrappers/tc_stat_wrapper.py
@@ -115,7 +115,9 @@ def create_c_dict(self):
if not c_dict['LOOKIN_DIR']:
self.log_error("TC_STAT_LOOKIN_DIR must be set")
- c_dict['OUTPUT_DIR'] = self.config.getdir('TC_STAT_OUTPUT_DIR')
+ c_dict['OUTPUT_DIR'] = self.config.getdir('TC_STAT_OUTPUT_DIR', '')
+ if not c_dict['OUTPUT_DIR']:
+ self.log_error("TC_STAT_OUTPUT_DIR must be set")
c_dict['JOBS'] = getlist(self.config.getraw('config',
'TC_STAT_JOB_ARGS',
@@ -124,16 +126,8 @@ def create_c_dict(self):
self.log_error('No job arguments defined. '
'Please set TC_STAT_JOB_ARGS')
- c_dict['CONFIG_FILE'] = self.config.getstr('config',
- 'TC_STAT_CONFIG_FILE',
- '')
- if not c_dict['CONFIG_FILE']:
- default_config = os.path.join(self.config.getdir('PARM_BASE'),
- 'met_config',
- 'TCStatConfig_wrapped')
- self.logger.debug("TC_STAT_CONFIG_FILE not set. Using "
- f"{default_config}")
- c_dict['CONFIG_FILE'] = default_config
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('TCStatConfig_wrapped')
self.handle_description()
diff --git a/metplus/wrappers/tcrmw_wrapper.py b/metplus/wrappers/tcrmw_wrapper.py
index 5fcca91368..0db3f864c8 100755
--- a/metplus/wrappers/tcrmw_wrapper.py
+++ b/metplus/wrappers/tcrmw_wrapper.py
@@ -60,8 +60,9 @@ def create_c_dict(self):
'LOG_TC_RMW_VERBOSITY',
c_dict['VERBOSITY'])
c_dict['ALLOW_MULTIPLE_FILES'] = True
- c_dict['CONFIG_FILE'] = self.config.getraw('config',
- 'TC_RMW_CONFIG_FILE', '')
+
+ # get the MET config file path or use default
+ c_dict['CONFIG_FILE'] = self.get_config_file('TCRMWConfig_wrapped')
c_dict['INPUT_DIR'] = self.config.getdir('TC_RMW_INPUT_DIR', '')
c_dict['INPUT_TEMPLATE'] = self.config.getraw('filename_templates',
diff --git a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py b/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py
index 0c60d95834..1c63b88104 100755
--- a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py
+++ b/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py
@@ -53,6 +53,7 @@ def run_omi_steps(inlabel, olr_filetxt, spd, EOF1, EOF2, oplot_dir):
olr_input_files = olr_input_files[1:]
# Read in the netCDF data from a list of files
+
netcdf_reader = read_netcdf.ReadNetCDF()
ds_orig = netcdf_reader.read_into_xarray(olr_input_files)