From 03975e09350b387a3bae0311a7c03e7a331ea1e9 Mon Sep 17 00:00:00 2001 From: Cory Martin Date: Wed, 16 Mar 2022 16:42:13 -0400 Subject: [PATCH 1/5] Start of attempt for CMake and python norms test --- .github/workflows/pynorms.yaml | 23 ++++++++++++ .pycodestyle | 6 ++++ CMakeLists.txt | 8 +++++ test/CMakeLists.txt | 3 ++ ush/check_yaml_keys.py | 66 ++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 .github/workflows/pynorms.yaml create mode 100644 .pycodestyle create mode 100644 CMakeLists.txt create mode 100644 test/CMakeLists.txt create mode 100644 ush/check_yaml_keys.py diff --git a/.github/workflows/pynorms.yaml b/.github/workflows/pynorms.yaml new file mode 100644 index 000000000..4d69238ae --- /dev/null +++ b/.github/workflows/pynorms.yaml @@ -0,0 +1,23 @@ +name: Check Python Coding Norms +on: [push, pull_request] + +jobs: + check_norms: + runs-on: ubuntu-latest + name: Check Python coding norms with pycodestyle + + steps: + + - name: Install dependencies + run: | + pip install --upgrade pip + pip install pycodestyle + - name: Checkout + uses: actions/checkout@v2 + with: + path: GDASapp + + - name: Run pycodestyle + run: | + cd $GITHUB_WORKSPACE/GDASapp + pycodestyle -v --config ./.pycodestyle . diff --git a/.pycodestyle b/.pycodestyle new file mode 100644 index 000000000..a56c7ee72 --- /dev/null +++ b/.pycodestyle @@ -0,0 +1,6 @@ +[pycodestyle] +count = False +ignore = E226,E401,E402,W504 +max-line-length = 160 +statistics = True +exclude = Experimental \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..1c589cff3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.10) + +# set the project name +project(GDAS) + +find_package(Python3 REQUIRED COMPONENTS Interpreter) + +enable_testing() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 000000000..b087aecc6 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,3 @@ +add_test(NAME test_check_yaml_keys + COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/ush/check_yaml_keys.py + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test/) \ No newline at end of file diff --git a/ush/check_yaml_keys.py b/ush/check_yaml_keys.py new file mode 100644 index 000000000..bf7673bdf --- /dev/null +++ b/ush/check_yaml_keys.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# compare keys between two YAML files +import argparse +import logging +import os +import yaml + +def check_yaml(YAMLref, YAMLtest, checkValues=False): + assert os.path.exists(YAMLref), f"File {YAMLref} not found." + assert os.path.exists(YAMLtest), f"File {YAMLtest} not found." + logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S') + logging.info(f'Comparing {YAMLtest} against {YAMLref}...') + # load reference file + try: + with open(YAMLref, 'r') as YAMLref_opened: + ref_dict = yaml.safe_load(YAMLref_opened) + except Exception as e: + logging.error(f'Error occurred when attempting to load: {YAMLref}, error: {e}') + # load file to test + try: + with open(YAMLtest, 'r') as YAMLtest_opened: + test_dict = yaml.safe_load(YAMLtest_opened) + except Exception as e: + logging.error(f'Error occurred when attempting to load: {YAMLtest}, error: {e}') + # loop through top level of YAML + compare_dict('', ref_dict, test_dict, checkValues) + +def compare_dict(rootkey, dict1, dict2, checkValues): + for key, value in dict1.items(): + keypath = f"{rootkey}/{key}" + if key not in dict2: + logging.error(f"'{keypath}' not in test file.") + else: + if isinstance(value, dict): + compare_dict(keypath, value, dict2[key], checkValues) + elif isinstance(value, list): + compare_list(keypath, value, dict2[key], checkValues) + else: + if checkValues: + if value != dict2[key]: + logging.warning(f"{keypath}: {dict2[key]} != {value}") + +def compare_list(rootkey, list1, list2, checkValues): + if len(list2) != len(list1): + logging.error(f"{rootkey} len={len(list2)} != {len(list1)}") + for i, item in enumerate(list1): + newkey = f"{rootkey}[{i}]" + if i+1 <= len(list2): + if isinstance(item, dict) and i+1 <= len(list2): + compare_dict(newkey, item, list2[i], checkValues) + elif isinstance(item, list): + compare_list(newkey, item, list2[i], checkValues) + else: + if checkValues: + if item != list2[i]: + logging.warning(f"{rootkey}/{i}: {list2[i]} != {item}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('YAMLref', type=str, help='Reference YAML file') + parser.add_argument('YAMLtest', type=str, help='YAML file to compare to reference') + parser.add_argument("--checkvalues", help="Check values in addition to keys", + action="store_true") + args = parser.parse_args() + check_yaml(args.YAMLref, args.YAMLtest, args.checkvalues) From f1353bc5bbdb6b3f2585da8185dbb229bc9f6162 Mon Sep 17 00:00:00 2001 From: Cory Martin Date: Wed, 16 Mar 2022 16:43:18 -0400 Subject: [PATCH 2/5] Fix coding norms --- ush/check_yaml_keys.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ush/check_yaml_keys.py b/ush/check_yaml_keys.py index bf7673bdf..21c0745df 100644 --- a/ush/check_yaml_keys.py +++ b/ush/check_yaml_keys.py @@ -5,6 +5,7 @@ import os import yaml + def check_yaml(YAMLref, YAMLtest, checkValues=False): assert os.path.exists(YAMLref), f"File {YAMLref} not found." assert os.path.exists(YAMLtest), f"File {YAMLtest} not found." @@ -25,6 +26,7 @@ def check_yaml(YAMLref, YAMLtest, checkValues=False): # loop through top level of YAML compare_dict('', ref_dict, test_dict, checkValues) + def compare_dict(rootkey, dict1, dict2, checkValues): for key, value in dict1.items(): keypath = f"{rootkey}/{key}" @@ -40,6 +42,7 @@ def compare_dict(rootkey, dict1, dict2, checkValues): if value != dict2[key]: logging.warning(f"{keypath}: {dict2[key]} != {value}") + def compare_list(rootkey, list1, list2, checkValues): if len(list2) != len(list1): logging.error(f"{rootkey} len={len(list2)} != {len(list1)}") From bf7bd39737217bc5e7ca16d19aeb06efac2999da Mon Sep 17 00:00:00 2001 From: CoryMartin-NOAA Date: Wed, 16 Mar 2022 21:03:07 +0000 Subject: [PATCH 3/5] Working first unit test --- .github/workflows/pynorms.yaml | 4 +-- .github/workflows/unittests.yaml | 31 ++++++++++++++++++++++++ CMakeLists.txt | 2 ++ test/CMakeLists.txt | 4 +-- test/testinput/check_yaml_keys_ref.yaml | 12 +++++++++ test/testinput/check_yaml_keys_test.yaml | 4 +++ 6 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/unittests.yaml create mode 100644 test/testinput/check_yaml_keys_ref.yaml create mode 100644 test/testinput/check_yaml_keys_test.yaml diff --git a/.github/workflows/pynorms.yaml b/.github/workflows/pynorms.yaml index 4d69238ae..8368ad714 100644 --- a/.github/workflows/pynorms.yaml +++ b/.github/workflows/pynorms.yaml @@ -2,7 +2,7 @@ name: Check Python Coding Norms on: [push, pull_request] jobs: - check_norms: + check_pynorms: runs-on: ubuntu-latest name: Check Python coding norms with pycodestyle @@ -15,7 +15,7 @@ jobs: - name: Checkout uses: actions/checkout@v2 with: - path: GDASapp + path: GDASapp - name: Run pycodestyle run: | diff --git a/.github/workflows/unittests.yaml b/.github/workflows/unittests.yaml new file mode 100644 index 000000000..c3fda455f --- /dev/null +++ b/.github/workflows/unittests.yaml @@ -0,0 +1,31 @@ +name: Run Unit Tests +on: [push, pull_request] + +jobs: + ctests: + runs-on: ubuntu-latest + name: Run Unit Tests with ctest + + steps: + + - name: Checkout + uses: actions/checkout@v2 + with: + path: GDASapp + + - name: Configure with cmake + run: | + cd $GITHUB_WORKSPACE/GDASapp + mkdir build + cd build + cmake ../ + + - name: Build GDASapp + run: | + cd $GITHUB_WORKSPACE/GDASapp/build + make + + - name: Run ctest + run: | + cd $GITHUB_WORKSPACE/GDASapp/build + ctest diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c589cff3..9a1fb25f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,3 +6,5 @@ project(GDAS) find_package(Python3 REQUIRED COMPONENTS Interpreter) enable_testing() + +add_subdirectory(test) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b087aecc6..07d818bc9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,3 @@ add_test(NAME test_check_yaml_keys - COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/ush/check_yaml_keys.py - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test/) \ No newline at end of file + COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/ush/check_yaml_keys.py ${CMAKE_SOURCE_DIR}/test/testinput/check_yaml_keys_ref.yaml ${CMAKE_SOURCE_DIR}/test/testinput/check_yaml_keys_test.yaml + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test/) diff --git a/test/testinput/check_yaml_keys_ref.yaml b/test/testinput/check_yaml_keys_ref.yaml new file mode 100644 index 000000000..142eea99f --- /dev/null +++ b/test/testinput/check_yaml_keys_ref.yaml @@ -0,0 +1,12 @@ +app: GDAS +components: +- name: atmosphere + model: FV3 +- name: ocean + model: MOM6 +- name: ice + model: CICE6 +- name: aerosols + model: GOCART +- name: land + model: noah diff --git a/test/testinput/check_yaml_keys_test.yaml b/test/testinput/check_yaml_keys_test.yaml new file mode 100644 index 000000000..646bd03bd --- /dev/null +++ b/test/testinput/check_yaml_keys_test.yaml @@ -0,0 +1,4 @@ +app: GDAS +components: +- name: atmosphere + model: FV3 From 22eb82507fb12c3101d509c3dd055c64dc0cc7cc Mon Sep 17 00:00:00 2001 From: Cory Martin Date: Wed, 16 Mar 2022 17:31:19 -0400 Subject: [PATCH 4/5] ensure GDASApp everywhere --- .github/workflows/pynorms.yaml | 4 ++-- .github/workflows/unittests.yaml | 10 +++++----- .pycodestyle | 2 +- CMakeLists.txt | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pynorms.yaml b/.github/workflows/pynorms.yaml index 8368ad714..95c790b7b 100644 --- a/.github/workflows/pynorms.yaml +++ b/.github/workflows/pynorms.yaml @@ -15,9 +15,9 @@ jobs: - name: Checkout uses: actions/checkout@v2 with: - path: GDASapp + path: GDASApp - name: Run pycodestyle run: | - cd $GITHUB_WORKSPACE/GDASapp + cd $GITHUB_WORKSPACE/GDASApp pycodestyle -v --config ./.pycodestyle . diff --git a/.github/workflows/unittests.yaml b/.github/workflows/unittests.yaml index c3fda455f..6a74e4b4f 100644 --- a/.github/workflows/unittests.yaml +++ b/.github/workflows/unittests.yaml @@ -11,21 +11,21 @@ jobs: - name: Checkout uses: actions/checkout@v2 with: - path: GDASapp + path: GDASApp - name: Configure with cmake run: | - cd $GITHUB_WORKSPACE/GDASapp + cd $GITHUB_WORKSPACE/GDASApp mkdir build cd build cmake ../ - - name: Build GDASapp + - name: Build GDASApp run: | - cd $GITHUB_WORKSPACE/GDASapp/build + cd $GITHUB_WORKSPACE/GDASApp/build make - name: Run ctest run: | - cd $GITHUB_WORKSPACE/GDASapp/build + cd $GITHUB_WORKSPACE/GDASApp/build ctest diff --git a/.pycodestyle b/.pycodestyle index a56c7ee72..162186cb7 100644 --- a/.pycodestyle +++ b/.pycodestyle @@ -3,4 +3,4 @@ count = False ignore = E226,E401,E402,W504 max-line-length = 160 statistics = True -exclude = Experimental \ No newline at end of file +exclude = Experimental diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a1fb25f9..a5598a46e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.10) # set the project name -project(GDAS) +project(GDASApp) find_package(Python3 REQUIRED COMPONENTS Interpreter) From 815310b32f5c98da2ea9d0b36d7315ea73693a8b Mon Sep 17 00:00:00 2001 From: Cory Martin Date: Wed, 16 Mar 2022 17:32:45 -0400 Subject: [PATCH 5/5] CMAKE to PROJECT --- test/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 07d818bc9..14fdb5e9c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,3 @@ add_test(NAME test_check_yaml_keys - COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/ush/check_yaml_keys.py ${CMAKE_SOURCE_DIR}/test/testinput/check_yaml_keys_ref.yaml ${CMAKE_SOURCE_DIR}/test/testinput/check_yaml_keys_test.yaml - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test/) + COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/ush/check_yaml_keys.py ${PROJECT_SOURCE_DIR}/test/testinput/check_yaml_keys_ref.yaml ${PROJECT_SOURCE_DIR}/test/testinput/check_yaml_keys_test.yaml + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/test/)