From ac4806c737f41926b4d97620f629b4c084c45434 Mon Sep 17 00:00:00 2001 From: Hoang Tung Dinh Date: Mon, 16 Sep 2024 17:25:43 +0200 Subject: [PATCH 1/5] Refactor to use one checker per rule (#30) Signed-off-by: hoangtungdinh <11166240+hoangtungdinh@users.noreply.github.com> --- README.md | 33 ++- checker_bundle_doc.md | 98 +++++++- poetry.lock | 217 ++++++++--------- qc_otx/checks/core_checker/__init__.py | 2 - qc_otx/checks/core_checker/core_checker.py | 59 ----- qc_otx/checks/core_checker/core_constants.py | 1 - .../document_name_matches_filename.py | 36 ++- .../document_name_package_uniqueness.py | 46 ++-- ..._specification_if_no_realisation_exists.py | 32 +-- .../mandatory_constant_initialization.py | 33 +-- ...of_imported_document_data_model_version.py | 47 ++-- .../core_checker/no_dead_import_links.py | 26 +-- .../checks/core_checker/no_unused_imports.py | 29 +-- .../no_use_of_undefined_import_prefixes.py | 38 ++- .../core_checker/public_main_procedure.py | 34 +-- .../checks/core_checker/unique_node_names.py | 33 +-- qc_otx/checks/data_type_checker/__init__.py | 2 - .../accessing_structure_elements.py | 35 +-- .../correct_target_for_structure_element.py | 27 +-- .../data_type_checker/data_type_checker.py | 43 ---- .../data_type_checker/data_type_constants.py | 1 - .../checks/state_machine_checker/__init__.py | 2 - ...stinguished_initial_and_completed_state.py | 56 +++-- .../mandatory_target_state.py | 47 ++-- .../mandatory_transition.py | 50 ++-- .../mandatory_trigger.py | 49 ++-- .../no_procedure_realization.py | 40 ++-- .../no_target_state_for_completed_state.py | 54 +++-- .../state_machine_checker.py | 51 ---- .../state_machine_constants.py | 1 - qc_otx/checks/utils.py | 19 +- qc_otx/checks/zip_file_checker/__init__.py | 2 - .../zip_file_checker/type_safe_unzip_file.py | 33 ++- .../zip_file_checker/type_safe_zip_file.py | 34 +-- .../zip_file_checker/zip_file_checker.py | 43 ---- .../zip_file_checker/zip_file_constants.py | 1 - qc_otx/main.py | 221 ++++++++++++++---- tests/test_core_checks.py | 198 +++++++++++++++- tests/test_data_type_checks.py | 33 ++- tests/test_state_machine_checks.py | 88 ++++++- tests/test_utils.py | 1 - tests/test_zip_file_checks.py | 25 +- 42 files changed, 1140 insertions(+), 780 deletions(-) delete mode 100644 qc_otx/checks/core_checker/core_checker.py delete mode 100644 qc_otx/checks/core_checker/core_constants.py delete mode 100644 qc_otx/checks/data_type_checker/data_type_checker.py delete mode 100644 qc_otx/checks/data_type_checker/data_type_constants.py delete mode 100644 qc_otx/checks/state_machine_checker/state_machine_checker.py delete mode 100644 qc_otx/checks/state_machine_checker/state_machine_constants.py delete mode 100644 qc_otx/checks/zip_file_checker/zip_file_checker.py delete mode 100644 qc_otx/checks/zip_file_checker/zip_file_constants.py diff --git a/README.md b/README.md index 6e0ea00..59cd6f2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # asam-qc-otx -This project implements the [ASAM Quality Checker OTX library](checker_bundle_doc.md). +This project implements the [OTX Checker Bundle](checker_bundle_doc.md) for the ASAM Quality Checker project. The ASAM Quality Checker OTX library contains a short representative list of check examples for [Open Test sequence eXchange (OTX)](https://report.asam.net/otx-iso-13209-open-test-sequence-exchange-format) to showcase the functionality and implementation (it shall not be a reference implementation) for the ASAM Quality Checker project. @@ -29,8 +29,11 @@ asam-qc-otx can be installed using pip. pip install asam-qc-otx@git+https://github.com/asam-ev/qc-otx@main ``` -**Note**: To install from different sources, you can replace `@main` with -your desired target. For example, `develop` branch as `@develop`. +**Note:** The above command will install `asam-qc-otx` from the `main` branch. If you want to install `asam-qc-otx` from another branch or tag, replace `@main` with the desired branch or tag. It is also possible to install from a local directory. + +```bash +pip install /home/user/qc-otx +``` To run the application: @@ -108,10 +111,26 @@ An example configuration file for using this Checker Bundle within the ASAM Qual - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/checker_bundle_doc.md b/checker_bundle_doc.md index 94958f5..ae5cd2b 100644 --- a/checker_bundle_doc.md +++ b/checker_bundle_doc.md @@ -5,46 +5,126 @@ ## Parameters -* InputFile: +* InputFile ## Checkers -### core_otx +### check_asam_otx_core_chk_001_document_name_matches_filename -* Description: Check if core properties of input file are properly set +* Description: For OTX documents stored in a file system, the attribute name of the root element should match the filename of the containing file (without the extension '.otx'). * Addressed rules: * asam.net:otx:1.0.0:core.chk_001.document_name_matches_filename + +### check_asam_otx_core_chk_002_document_name_package_uniqueness + +* Description: The value of the attribute name shall be unique within the scope of all OTX documents belonging to the same package. +* Addressed rules: * asam.net:otx:1.0.0:core.chk_002.document_name_package_uniqueness + +### check_asam_otx_core_chk_003_no_dead_import_links + +* Description: Imported OTX documents (referenced by package name and document name via elements) should exist and should be accessible. +* Addressed rules: * asam.net:otx:1.0.0:core.chk_003.no_dead_import_links + +### check_asam_otx_core_chk_004_no_unused_imports + +* Description: An imported OTX document should be used at least once in the importing document. +* Addressed rules: * asam.net:otx:1.0.0:core.chk_004.no_unused_imports + +### check_asam_otx_core_chk_005_no_use_of_undefined_import_prefixes + +* Description: If an imported name is accessed by prefix in an OtxLink type attribute, the corresponding prefix definition shall exist in an element. +* Addressed rules: * asam.net:otx:1.0.0:core.chk_005.no_use_of_undefined_import_prefixes + +### check_asam_otx_core_chk_006_match_of_imported_document_data_model_version + +* Description: An imported OTX document (imported by an element) shall be bound to the same data model version as the importing document. +* Addressed rules: * asam.net:otx:1.0.0:core.chk_006.match_of_imported_document_data_model_version + +### check_asam_otx_core_chk_007_have_specification_if_no_realisation_exists + +* Description: For all elements with specification and realisation parts in an OTX document: if there is no given, the according element should exist and have content (no empty string). +* Addressed rules: * asam.net:otx:1.0.0:core.chk_007.have_specification_if_no_realisation_exists + +### check_asam_otx_core_chk_008_public_main_procedure + +* Description: he value of attribute visibility shall always be 'PUBLIC' if the procedure name is 'main'. +* Addressed rules: * asam.net:otx:1.0.0:core.chk_008.public_main_procedure + +### check_asam_otx_core_chk_009_mandatory_constant_initialization + +* Description: Constant declarations shall always be initialized. +* Addressed rules: * asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization + +### check_asam_otx_core_chk_010_unique_node_names + +* Description: The value of a nodes name attribute should be unique among all nodes in a procedure. +* Addressed rules: * asam.net:otx:1.0.0:core.chk_010.unique_node_names -### data_type_otx +### check_asam_otx_data_type_chk_001_accessing_structure_elements -* Description: Check if data_type properties of input file are properly set +* Description: Accessing structure elements is only allowed via StepByName using matching string literals. * Addressed rules: * asam.net:otx:1.0.0:data_type.chk_001.accessing_structure_elements + +### check_asam_otx_data_type_chk_008_correct_target_for_structure_element + +* Description: When referring to a structure element, an existing name of the referenced StructureSignature shall be used. +* Addressed rules: * asam.net:otx:1.0.0:data_type.chk_008.correct_target_for_structure_element -### zip_file_otx +### check_asam_otx_zip_file_chk_002_type_safe_zip_file -* Description: Check if zip_file properties of input file are properly set +* Description: In a ZipFile action, the list described by ListTerm shall have a data type of . * Addressed rules: * asam.net:otx:1.0.0:zip_file.chk_002.type_safe_zip_file + +### check_asam_otx_zip_file_chk_001_type_safe_unzip_file + +* Description: In an UnZipFile action, the list described by ListTerm shall have a data type of . +* Addressed rules: * asam.net:otx:1.0.0:zip_file.chk_001.type_safe_unzip_file -### state_machine_otx +### check_asam_otx_state_machine_chk_001_no_procedure_realization -* Description: Check if state_machine properties of input file are properly set +* Description: A StateMachineProcedure shall not have a ProcedureRealisation. * Addressed rules: * asam.net:otx:1.0.0:state_machine.chk_001.no_procedure_realization + +### check_asam_otx_state_machine_chk_002_mandatory_target_state + +* Description: Each state except the completed state shall have a target state. +* Addressed rules: * asam.net:otx:1.0.0:state_machine.chk_002.mandatory_target_state + +### check_asam_otx_state_machine_chk_003_no_target_state_for_completed_state + +* Description: After finishing the completed state the procedure is finished and shall return to the caller. Therefore the completed state shall not have a target state. +* Addressed rules: * asam.net:otx:1.0.0:state_machine.chk_003.no_target_state_for_completed_state + +### check_asam_otx_state_machine_chk_005_mandatory_transition + +* Description: Each state except the completed state shall have at least one transition. +* Addressed rules: * asam.net:otx:1.0.0:state_machine.chk_005.mandatory_transition + +### check_asam_otx_state_machine_chk_004_mandatory_trigger + +* Description: Each state except the completed state shall have at least one trigger. +* Addressed rules: * asam.net:otx:1.0.0:state_machine.chk_004.mandatory_trigger + +### check_asam_otx_state_machine_chk_006_distinguished_initial_and_completed_state + +* Description: The values of the mandatory initialState and optional completedState attributes shall be distinguished. +* Addressed rules: * asam.net:otx:1.0.0:state_machine.chk_006.distinguished_initial_and_completed_state diff --git a/poetry.lock b/poetry.lock index 3c92d01..61953b6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -29,7 +29,7 @@ pydantic-xml = "^2.11.0" type = "git" url = "https://github.com/asam-ev/qc-baselib-py.git" reference = "develop" -resolved_reference = "fba6e49096d14ba31f5bf17e9e5efe6020eceb5c" +resolved_reference = "f7ea664805bcce456ebd0ede93c852dd389c1944" [[package]] name = "black" @@ -316,19 +316,19 @@ files = [ [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.3" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.3-py3-none-any.whl", hash = "sha256:50a5450e2e84f44539718293cbb1da0a0885c9d14adf21b77bae4e66fc99d9b5"}, + {file = "platformdirs-4.3.3.tar.gz", hash = "sha256:d4e0b7d8ec176b341fb03cb11ca12d0276faa8c485f9cd218f613840463fc2c0"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -347,18 +347,18 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.8.2" +version = "2.9.1" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, - {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, + {file = "pydantic-2.9.1-py3-none-any.whl", hash = "sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612"}, + {file = "pydantic-2.9.1.tar.gz", hash = "sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.20.1" +annotated-types = ">=0.6.0" +pydantic-core = "2.23.3" typing-extensions = [ {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, {version = ">=4.6.1", markers = "python_version < \"3.13\""}, @@ -366,103 +366,104 @@ typing-extensions = [ [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.20.1" +version = "2.23.3" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, - {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, - {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, - {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, - {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, - {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, - {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, - {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, - {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, - {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, - {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, - {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, - {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, - {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, + {file = "pydantic_core-2.23.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6"}, + {file = "pydantic_core-2.23.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba"}, + {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee"}, + {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe"}, + {file = "pydantic_core-2.23.3-cp310-none-win32.whl", hash = "sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b"}, + {file = "pydantic_core-2.23.3-cp310-none-win_amd64.whl", hash = "sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83"}, + {file = "pydantic_core-2.23.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27"}, + {file = "pydantic_core-2.23.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8"}, + {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48"}, + {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5"}, + {file = "pydantic_core-2.23.3-cp311-none-win32.whl", hash = "sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1"}, + {file = "pydantic_core-2.23.3-cp311-none-win_amd64.whl", hash = "sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa"}, + {file = "pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305"}, + {file = "pydantic_core-2.23.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c"}, + {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c"}, + {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab"}, + {file = "pydantic_core-2.23.3-cp312-none-win32.whl", hash = "sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c"}, + {file = "pydantic_core-2.23.3-cp312-none-win_amd64.whl", hash = "sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b"}, + {file = "pydantic_core-2.23.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f"}, + {file = "pydantic_core-2.23.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855"}, + {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4"}, + {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d"}, + {file = "pydantic_core-2.23.3-cp313-none-win32.whl", hash = "sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8"}, + {file = "pydantic_core-2.23.3-cp313-none-win_amd64.whl", hash = "sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1"}, + {file = "pydantic_core-2.23.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d063c6b9fed7d992bcbebfc9133f4c24b7a7f215d6b102f3e082b1117cddb72c"}, + {file = "pydantic_core-2.23.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6cb968da9a0746a0cf521b2b5ef25fc5a0bee9b9a1a8214e0a1cfaea5be7e8a4"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbefe079a520c5984e30e1f1f29325054b59534729c25b874a16a5048028d16"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbaaf2ef20d282659093913da9d402108203f7cb5955020bd8d1ae5a2325d1c4"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb539d7e5dc4aac345846f290cf504d2fd3c1be26ac4e8b5e4c2b688069ff4cf"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e6f33503c5495059148cc486867e1d24ca35df5fc064686e631e314d959ad5b"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b07490bc2f6f2717b10c3969e1b830f5720b632f8ae2f3b8b1542394c47a8e"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03795b9e8a5d7fda05f3873efc3f59105e2dcff14231680296b87b80bb327295"}, + {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c483dab0f14b8d3f0df0c6c18d70b21b086f74c87ab03c59250dbf6d3c89baba"}, + {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b2682038e255e94baf2c473dca914a7460069171ff5cdd4080be18ab8a7fd6e"}, + {file = "pydantic_core-2.23.3-cp38-none-win32.whl", hash = "sha256:f4a57db8966b3a1d1a350012839c6a0099f0898c56512dfade8a1fe5fb278710"}, + {file = "pydantic_core-2.23.3-cp38-none-win_amd64.whl", hash = "sha256:13dd45ba2561603681a2676ca56006d6dee94493f03d5cadc055d2055615c3ea"}, + {file = "pydantic_core-2.23.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82da2f4703894134a9f000e24965df73cc103e31e8c31906cc1ee89fde72cbd8"}, + {file = "pydantic_core-2.23.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dd9be0a42de08f4b58a3cc73a123f124f65c24698b95a54c1543065baca8cf0e"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89b731f25c80830c76fdb13705c68fef6a2b6dc494402987c7ea9584fe189f5d"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6de1ec30c4bb94f3a69c9f5f2182baeda5b809f806676675e9ef6b8dc936f28"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb68b41c3fa64587412b104294b9cbb027509dc2f6958446c502638d481525ef"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c3980f2843de5184656aab58698011b42763ccba11c4a8c35936c8dd6c7068c"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94f85614f2cba13f62c3c6481716e4adeae48e1eaa7e8bac379b9d177d93947a"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:510b7fb0a86dc8f10a8bb43bd2f97beb63cffad1203071dc434dac26453955cd"}, + {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1eba2f7ce3e30ee2170410e2171867ea73dbd692433b81a93758ab2de6c64835"}, + {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b259fd8409ab84b4041b7b3f24dcc41e4696f180b775961ca8142b5b21d0e70"}, + {file = "pydantic_core-2.23.3-cp39-none-win32.whl", hash = "sha256:40d9bd259538dba2f40963286009bf7caf18b5112b19d2b55b09c14dde6db6a7"}, + {file = "pydantic_core-2.23.3-cp39-none-win_amd64.whl", hash = "sha256:5a8cd3074a98ee70173a8633ad3c10e00dcb991ecec57263aacb4095c5efb958"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e89513f014c6be0d17b00a9a7c81b1c426f4eb9224b15433f3d98c1a071f8433"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4f62c1c953d7ee375df5eb2e44ad50ce2f5aff931723b398b8bc6f0ac159791a"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2718443bc671c7ac331de4eef9b673063b10af32a0bb385019ad61dcf2cc8f6c"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d90e08b2727c5d01af1b5ef4121d2f0c99fbee692c762f4d9d0409c9da6541"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b676583fc459c64146debea14ba3af54e540b61762dfc0613dc4e98c3f66eeb"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:50e4661f3337977740fdbfbae084ae5693e505ca2b3130a6d4eb0f2281dc43b8"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:68f4cf373f0de6abfe599a38307f4417c1c867ca381c03df27c873a9069cda25"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:59d52cf01854cb26c46958552a21acb10dd78a52aa34c86f284e66b209db8cab"}, + {file = "pydantic_core-2.23.3.tar.gz", hash = "sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690"}, ] [package.dependencies] @@ -470,13 +471,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-xml" -version = "2.11.0" +version = "2.12.1" description = "pydantic xml extension" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_xml-2.11.0-py3-none-any.whl", hash = "sha256:033b2b997a99bdb18ab93d7ed66a5bc9ec490753afc011f084bd625ad2d0bdfd"}, - {file = "pydantic_xml-2.11.0.tar.gz", hash = "sha256:7fbe816b8251b45aabe0c11992fc52e2921afd8f46f256b3f60ed82f869361da"}, + {file = "pydantic_xml-2.12.1-py3-none-any.whl", hash = "sha256:5de8394dde00d00a899b85fd8e0b915e6f144a068675d8efcbaa225fdcce3880"}, + {file = "pydantic_xml-2.12.1.tar.gz", hash = "sha256:31623e9b287ef9eb1dda4caa92e893e3ac977f0327e1d76fd8a36879e455cea1"}, ] [package.dependencies] @@ -489,13 +490,13 @@ lxml = ["lxml (>=4.9.0)"] [[package]] name = "pytest" -version = "8.3.2" +version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [package.dependencies] diff --git a/qc_otx/checks/core_checker/__init__.py b/qc_otx/checks/core_checker/__init__.py index e41094c..c35845d 100644 --- a/qc_otx/checks/core_checker/__init__.py +++ b/qc_otx/checks/core_checker/__init__.py @@ -1,5 +1,3 @@ -from . import core_constants as core_constants -from . import core_checker as core_checker from . import document_name_matches_filename as document_name_matches_filename from . import document_name_package_uniqueness as document_name_package_uniqueness from . import no_unused_imports as no_unused_imports diff --git a/qc_otx/checks/core_checker/core_checker.py b/qc_otx/checks/core_checker/core_checker.py deleted file mode 100644 index aff6c87..0000000 --- a/qc_otx/checks/core_checker/core_checker.py +++ /dev/null @@ -1,59 +0,0 @@ -import logging - -from lxml import etree - -from qc_baselib import Configuration, Result, StatusType - -from qc_otx import constants -from qc_otx.checks import utils, models - -from qc_otx.checks.core_checker import ( - core_constants, - document_name_matches_filename, - document_name_package_uniqueness, - no_dead_import_links, - no_unused_imports, - have_specification_if_no_realisation_exists, - public_main_procedure, - mandatory_constant_initialization, - unique_node_names, - no_use_of_undefined_import_prefixes, - match_of_imported_document_data_model_version, -) - - -def run_checks(checker_data: models.CheckerData) -> None: - logging.info("Executing core checks") - - checker_data.result.register_checker( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - description="Check if core properties of input file are properly set", - summary="", - ) - - rule_list = [ - document_name_matches_filename.check_rule, # Chk001 - document_name_package_uniqueness.check_rule, # Chk002 - no_dead_import_links.check_rule, # Chk003 - no_unused_imports.check_rule, # Chk004 - no_use_of_undefined_import_prefixes.check_rule, # Chk005 - match_of_imported_document_data_model_version.check_rule, # Chk006 - have_specification_if_no_realisation_exists.check_rule, # Chk007 - public_main_procedure.check_rule, # Chk008 - mandatory_constant_initialization.check_rule, # Chk009 - unique_node_names.check_rule, # Chk010 - ] - - for rule in rule_list: - rule(checker_data=checker_data) - - logging.info( - f"Issues found - {checker_data.result.get_checker_issue_count(checker_bundle_name=constants.BUNDLE_NAME, checker_id=core_constants.CHECKER_ID)}" - ) - - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - status=StatusType.COMPLETED, - ) diff --git a/qc_otx/checks/core_checker/core_constants.py b/qc_otx/checks/core_checker/core_constants.py deleted file mode 100644 index 4c11ec1..0000000 --- a/qc_otx/checks/core_checker/core_constants.py +++ /dev/null @@ -1 +0,0 @@ -CHECKER_ID = "core_otx" diff --git a/qc_otx/checks/core_checker/document_name_matches_filename.py b/qc_otx/checks/core_checker/document_name_matches_filename.py index c8bc232..b393960 100644 --- a/qc_otx/checks/core_checker/document_name_matches_filename.py +++ b/qc_otx/checks/core_checker/document_name_matches_filename.py @@ -1,18 +1,18 @@ import logging -from dataclasses import dataclass -from typing import List -from lxml import etree - -from qc_baselib import Configuration, Result, IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants -from qc_otx.checks import utils, models +from qc_otx.checks import models -from qc_otx.checks.core_checker import core_constants from pathlib import Path +CHECKER_ID = "check_asam_otx_core_chk_001_document_name_matches_filename" +CHECKER_DESCRIPTION = "For OTX documents stored in a file system, the attribute name of the root element should match the filename of the containing file (without the extension '.otx')." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_001.document_name_matches_filename" + def check_rule(checker_data: models.CheckerData) -> None: """ @@ -26,20 +26,18 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing document_name_matches_filename check") - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_001.document_name_matches_filename", - ) - root = checker_data.input_file_xml_root root_attrib = root.getroot().attrib if "name" not in root_attrib: logging.error("No name attribute find in otx root node. Abort...") + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return document_name = root_attrib["name"] @@ -52,15 +50,15 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when document name does not match file name", level=IssueSeverity.WARNING, - rule_uid=rule_uid, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath="/otx", description=f"Invalid otx name {document_name} detected. Do not match filename {filename}", diff --git a/qc_otx/checks/core_checker/document_name_package_uniqueness.py b/qc_otx/checks/core_checker/document_name_package_uniqueness.py index 15bbaa2..988bb26 100644 --- a/qc_otx/checks/core_checker/document_name_package_uniqueness.py +++ b/qc_otx/checks/core_checker/document_name_package_uniqueness.py @@ -1,17 +1,19 @@ import logging, os -from dataclasses import dataclass from typing import List from lxml import etree -from qc_baselib import Configuration, Result, IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants -from qc_otx.checks import utils, models +from qc_otx.checks import models -from qc_otx.checks.core_checker import core_constants -from pathlib import Path + +CHECKER_ID = "check_asam_otx_core_chk_002_document_name_package_uniqueness" +CHECKER_DESCRIPTION = "The value of the attribute name shall be unique within the scope of all OTX documents belonging to the same package." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_002.document_name_package_uniqueness" def find_otx_files(directory: str) -> List: @@ -55,25 +57,30 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing document_name_package_uniqueness check") - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_002.document_name_package_uniqueness", - ) - root = checker_data.input_file_xml_root.getroot() document_name = root.get("name") if document_name is None: logging.error("No name attribute find in otx root node. Abort...") + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return package_name = root.get("package") if package_name is None: logging.error("No package attribute find in otx root node. Abort...") + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return document_package_dot_name = package_name + "." + document_name @@ -107,6 +114,13 @@ def check_rule(checker_data: models.CheckerData) -> None: f"Error in setting package root {package_root}. Folder not found. Abort..." ) os.chdir(previous_wd) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return # Collect all otx file path from package root package_otx_files = find_otx_files(package_root) @@ -124,10 +138,10 @@ def check_rule(checker_data: models.CheckerData) -> None: if not is_valid: checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when otx name is reused in the same package", level=IssueSeverity.ERROR, - rule_uid=rule_uid, + rule_uid=RULE_UID, ) os.chdir(previous_wd) diff --git a/qc_otx/checks/core_checker/have_specification_if_no_realisation_exists.py b/qc_otx/checks/core_checker/have_specification_if_no_realisation_exists.py index 0a0e35a..2eec8a5 100644 --- a/qc_otx/checks/core_checker/have_specification_if_no_realisation_exists.py +++ b/qc_otx/checks/core_checker/have_specification_if_no_realisation_exists.py @@ -1,15 +1,16 @@ -import logging, os +import logging -from typing import List -from lxml import etree - -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.core_checker import core_constants +CHECKER_ID = "check_asam_otx_core_chk_007_have_specification_if_no_realisation_exists" +CHECKER_DESCRIPTION = "For all elements with specification and realisation parts in an OTX document: if there is no given, the according element should exist and have content (no empty string)." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_007.have_specification_if_no_realisation_exists" + NODES_WITH_SPECIFICATION_AND_REALISATION = [ "declaration", @@ -29,17 +30,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing have_specification_if_no_realisation_exists check") - issue_severity = IssueSeverity.WARNING - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_007.have_specification_if_no_realisation_exists", - ) - tree = checker_data.input_file_xml_root root = tree.getroot() @@ -70,15 +60,15 @@ def check_rule(checker_data: models.CheckerData) -> None: if not is_valid: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue to check if empty realisation have content in specification", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.WARNING, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Node {current_xpath} has no realisation and no specification or empty string in specification", diff --git a/qc_otx/checks/core_checker/mandatory_constant_initialization.py b/qc_otx/checks/core_checker/mandatory_constant_initialization.py index d85f918..aefc211 100644 --- a/qc_otx/checks/core_checker/mandatory_constant_initialization.py +++ b/qc_otx/checks/core_checker/mandatory_constant_initialization.py @@ -1,15 +1,14 @@ -import logging, os +import logging -from typing import List - -from lxml import etree - -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.core_checker import core_constants +CHECKER_ID = "check_asam_otx_core_chk_009_mandatory_constant_initialization" +CHECKER_DESCRIPTION = "Constant declarations shall always be initialized." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" def check_rule(checker_data: models.CheckerData) -> None: @@ -20,19 +19,7 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing mandatory_constant_initialization check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_009.mandatory_constant_initialization", - ) - tree = checker_data.input_file_xml_root - root = tree.getroot() # Use XPath to find all nodes constant constant_nodes = tree.xpath("//constant") @@ -49,15 +36,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getpath(constant_node) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when a constant is not initialized", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Constant {constant_name} at {current_xpath} is not initialized", diff --git a/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py b/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py index cb56af7..cb0e243 100644 --- a/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py +++ b/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py @@ -1,18 +1,19 @@ -import logging, os, re - -from typing import List +import logging, os from lxml import etree -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models, utils -from qc_otx.checks.core_checker import core_constants - -RULE_SEVERITY = IssueSeverity.ERROR +CHECKER_ID = "check_asam_otx_core_chk_006_match_of_imported_document_data_model_version" +CHECKER_DESCRIPTION = "An imported OTX document (imported by an element) shall be bound to the same data model version as the importing document." +CHECKER_PRECONDITIONS = set() +RULE_UID = ( + "asam.net:otx:1.0.0:core.chk_006.match_of_imported_document_data_model_version" +) def check_rule(checker_data: models.CheckerData) -> None: @@ -28,15 +29,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing match_of_imported_document_data_model_version check") - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_006.match_of_imported_document_data_model_version", - ) - input_file_path = checker_data.config.get_config_param("InputFile") tree = checker_data.input_file_xml_root root = tree.getroot() @@ -46,13 +38,28 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.error( "xmlns version not found in current document root. Skipping check.." ) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return + logging.debug(f"source_data_model_version: {source_data_model_version}") import_nodes = root.findall(".//import", namespaces=root.nsmap) if import_nodes is None: logging.error("No import nodes found. Skipping check..") + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return # Store previous working directory and move to config path dir for relative package paths @@ -83,15 +90,15 @@ def check_rule(checker_data: models.CheckerData) -> None: if has_issue: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when data model version of imported document is different than the one in current document", - level=RULE_SEVERITY, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Imported document {current_document} data model version {current_data_model_version} different than current model version {source_data_model_version}", diff --git a/qc_otx/checks/core_checker/no_dead_import_links.py b/qc_otx/checks/core_checker/no_dead_import_links.py index fe578e9..aac89c4 100644 --- a/qc_otx/checks/core_checker/no_dead_import_links.py +++ b/qc_otx/checks/core_checker/no_dead_import_links.py @@ -1,15 +1,14 @@ import logging, os -from typing import List - -from lxml import etree - -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.core_checker import core_constants +CHECKER_ID = "check_asam_otx_core_chk_003_no_dead_import_links" +CHECKER_DESCRIPTION = "Imported OTX documents (referenced by package name and document name via elements) should exist and should be accessible." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_003.no_dead_import_links" def check_rule(checker_data: models.CheckerData) -> None: @@ -22,15 +21,6 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.info("Executing no_dead_import_links check") - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_003.no_dead_import_links", - ) - tree = checker_data.input_file_xml_root root = tree.getroot() input_file_path = checker_data.config.get_config_param("InputFile") @@ -61,15 +51,15 @@ def check_rule(checker_data: models.CheckerData) -> None: if not import_file_exists: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when an imported otx document does not exists at specified package", level=IssueSeverity.ERROR, - rule_uid=rule_uid, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=import_xpath, description=f"Imported otx document [package: {import_package}, document:{import_document}, prefix:{import_prefix}] does not exists", diff --git a/qc_otx/checks/core_checker/no_unused_imports.py b/qc_otx/checks/core_checker/no_unused_imports.py index e8bfa91..02339f1 100644 --- a/qc_otx/checks/core_checker/no_unused_imports.py +++ b/qc_otx/checks/core_checker/no_unused_imports.py @@ -1,15 +1,19 @@ -import logging, os +import logging from typing import List -from lxml import etree - -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.core_checker import core_constants + +CHECKER_ID = "check_asam_otx_core_chk_004_no_unused_imports" +CHECKER_DESCRIPTION = ( + "An imported OTX document should be used at least once in the importing document." +) +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_004.no_unused_imports" def _is_prefix_never_used_in_attributes(attributes: List, prefix: str) -> bool: @@ -29,15 +33,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing no_unused_imports check") - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_004.no_unused_imports", - ) - tree = checker_data.input_file_xml_root root = tree.getroot() @@ -53,15 +48,15 @@ def check_rule(checker_data: models.CheckerData) -> None: if _is_prefix_never_used_in_attributes(otx_document_attributes, import_prefix): issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when an imported otx document is never used in the current otx", level=IssueSeverity.WARNING, - rule_uid=rule_uid, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=import_path, description=f"Imported otx document [package: {import_package}, document:{import_document}, prefix:{import_prefix}] is never used in current document", diff --git a/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py b/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py index d134570..8881fbb 100644 --- a/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py +++ b/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py @@ -1,17 +1,15 @@ -import logging, os +import logging -from typing import List - -from lxml import etree - -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models, utils -from qc_otx.checks.core_checker import core_constants +CHECKER_ID = "check_asam_otx_core_chk_005_no_use_of_undefined_import_prefixes" +CHECKER_DESCRIPTION = "If an imported name is accessed by prefix in an OtxLink type attribute, the corresponding prefix definition shall exist in an element." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_005.no_use_of_undefined_import_prefixes" -RULE_SEVERITY = IssueSeverity.ERROR OTX_LINK_ATTRIBUTES = set() OTX_LINK_ATTRIBUTES.add("implements") @@ -31,15 +29,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing no_use_of_undefined_import_prefixes check") - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_005.no_use_of_undefined_import_prefixes", - ) - tree = checker_data.input_file_xml_root root = tree.getroot() @@ -47,6 +36,13 @@ def check_rule(checker_data: models.CheckerData) -> None: if import_nodes is None: logging.error("No import nodes found. Skipping check..") + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return import_prefixes = [x.get("prefix") for x in import_nodes] @@ -71,15 +67,15 @@ def check_rule(checker_data: models.CheckerData) -> None: if has_issue: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when prefix definition does not exists in an import element", - level=RULE_SEVERITY, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=otx_link.xpath, description=f"Imported prefix {current_prefix} not found across import elements", diff --git a/qc_otx/checks/core_checker/public_main_procedure.py b/qc_otx/checks/core_checker/public_main_procedure.py index 574f444..d10a0a0 100644 --- a/qc_otx/checks/core_checker/public_main_procedure.py +++ b/qc_otx/checks/core_checker/public_main_procedure.py @@ -1,15 +1,15 @@ -import logging, os +import logging -from typing import List - -from lxml import etree - -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.core_checker import core_constants + +CHECKER_ID = "check_asam_otx_core_chk_008_public_main_procedure" +CHECKER_DESCRIPTION = "he value of attribute visibility shall always be 'PUBLIC' if the procedure name is 'main'." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" def check_rule(checker_data: models.CheckerData) -> None: @@ -20,19 +20,7 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing public_main_procedure check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_008.public_main_procedure", - ) - tree = checker_data.input_file_xml_root - root = tree.getroot() # Use XPath to find all nodes procedures procedure_nodes = tree.xpath(f"//procedure") @@ -51,15 +39,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getpath(procedure_node) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when procedure called main has not PUBLIC visibility", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Procedure at {current_xpath} is called main but its visibility is not PUBLIC", diff --git a/qc_otx/checks/core_checker/unique_node_names.py b/qc_otx/checks/core_checker/unique_node_names.py index 720d2ab..899749b 100644 --- a/qc_otx/checks/core_checker/unique_node_names.py +++ b/qc_otx/checks/core_checker/unique_node_names.py @@ -1,15 +1,14 @@ -import logging, os +import logging -from typing import List - -from lxml import etree - -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.core_checker import core_constants +CHECKER_ID = "check_asam_otx_core_chk_010_unique_node_names" +CHECKER_DESCRIPTION = "The value of a nodes name attribute should be unique among all nodes in a procedure." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:core.chk_010.unique_node_names" def check_rule(checker_data: models.CheckerData) -> None: @@ -30,19 +29,7 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing unique_node_names check") - issue_severity = IssueSeverity.WARNING - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="core.chk_010.unique_node_names", - ) - tree = checker_data.input_file_xml_root - root = tree.getroot() # Use XPath to find all nodes procedure procedure_nodes = tree.xpath("//procedure") @@ -76,15 +63,15 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when nodes with same attribute name are found in a procedure", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.WARNING, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=core_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=xpaths, description=f"Procedure {procedure_name} contains duplicated name.", diff --git a/qc_otx/checks/data_type_checker/__init__.py b/qc_otx/checks/data_type_checker/__init__.py index f759693..4a05b00 100644 --- a/qc_otx/checks/data_type_checker/__init__.py +++ b/qc_otx/checks/data_type_checker/__init__.py @@ -1,5 +1,3 @@ -from . import data_type_constants as data_type_constants -from . import data_type_checker as data_type_checker from . import accessing_structure_elements as accessing_structure_elements from . import ( correct_target_for_structure_element as correct_target_for_structure_element, diff --git a/qc_otx/checks/data_type_checker/accessing_structure_elements.py b/qc_otx/checks/data_type_checker/accessing_structure_elements.py index 6b89cd4..4a9daa0 100644 --- a/qc_otx/checks/data_type_checker/accessing_structure_elements.py +++ b/qc_otx/checks/data_type_checker/accessing_structure_elements.py @@ -1,15 +1,15 @@ -import logging, os +import logging -from typing import List - -from lxml import etree - -from qc_baselib import Result, IssueSeverity +from qc_baselib import IssueSeverity from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.data_type_checker import data_type_constants + +CHECKER_ID = "check_asam_otx_data_type_chk_001_accessing_structure_elements" +CHECKER_DESCRIPTION = "Accessing structure elements is only allowed via StepByName using matching string literals." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:data_type.chk_001.accessing_structure_elements" def check_rule(checker_data: models.CheckerData) -> None: @@ -27,22 +27,9 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing accessing_structure_elements check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=data_type_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="data_type.chk_001.accessing_structure_elements", - ) - tree = checker_data.input_file_xml_root - root = tree.getroot() # Use XPath to find all nodes procedure - declaration_nodes = tree.xpath("//declaration") signature_nodes = tree.xpath("//signature") signature_dict = dict() @@ -94,15 +81,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getelementpath(step_by_name_node) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=data_type_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when StepByName node accessing invalid fields", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=data_type_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Accessing {current_value} for variable {current_result_name} of type {current_variable_type} is not present in type definition", diff --git a/qc_otx/checks/data_type_checker/correct_target_for_structure_element.py b/qc_otx/checks/data_type_checker/correct_target_for_structure_element.py index 428d399..44839a5 100644 --- a/qc_otx/checks/data_type_checker/correct_target_for_structure_element.py +++ b/qc_otx/checks/data_type_checker/correct_target_for_structure_element.py @@ -5,7 +5,11 @@ from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.data_type_checker import data_type_constants + +CHECKER_ID = "check_asam_otx_data_type_chk_008_correct_target_for_structure_element" +CHECKER_DESCRIPTION = "When referring to a structure element, an existing name of the referenced StructureSignature shall be used." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:data_type.chk_008.correct_target_for_structure_element" def check_rule(checker_data: models.CheckerData) -> None: @@ -23,22 +27,9 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing correct_target_for_structure_element check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=data_type_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="data_type.chk_008.correct_target_for_structure_element", - ) - tree = checker_data.input_file_xml_root - root = tree.getroot() # Use XPath to find all nodes procedure - declaration_nodes = tree.xpath("//declaration") signature_nodes = tree.xpath("//signature") signature_dict = dict() @@ -88,15 +79,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getpath(structure_instance) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=data_type_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when invalid names is used in accessing structure element", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=data_type_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Accessing {current_value} for variable {structure_name} of type {current_variable_type} is not present in type definition", diff --git a/qc_otx/checks/data_type_checker/data_type_checker.py b/qc_otx/checks/data_type_checker/data_type_checker.py deleted file mode 100644 index b7194a6..0000000 --- a/qc_otx/checks/data_type_checker/data_type_checker.py +++ /dev/null @@ -1,43 +0,0 @@ -import logging - -from lxml import etree - -from qc_baselib import Configuration, Result, StatusType - -from qc_otx import constants -from qc_otx.checks import utils, models - -from qc_otx.checks.data_type_checker import ( - data_type_constants, - accessing_structure_elements, - correct_target_for_structure_element, -) - - -def run_checks(checker_data: models.CheckerData) -> None: - logging.info("Executing data_type checks") - - checker_data.result.register_checker( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=data_type_constants.CHECKER_ID, - description="Check if data_type properties of input file are properly set", - summary="", - ) - - rule_list = [ - accessing_structure_elements.check_rule, # Chk001 - correct_target_for_structure_element.check_rule, # Chk008 - ] - - for rule in rule_list: - rule(checker_data=checker_data) - - logging.info( - f"Issues found - {checker_data.result.get_checker_issue_count(checker_bundle_name=constants.BUNDLE_NAME, checker_id=data_type_constants.CHECKER_ID)}" - ) - - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=data_type_constants.CHECKER_ID, - status=StatusType.COMPLETED, - ) diff --git a/qc_otx/checks/data_type_checker/data_type_constants.py b/qc_otx/checks/data_type_checker/data_type_constants.py deleted file mode 100644 index 35975eb..0000000 --- a/qc_otx/checks/data_type_checker/data_type_constants.py +++ /dev/null @@ -1 +0,0 @@ -CHECKER_ID = "data_type_otx" diff --git a/qc_otx/checks/state_machine_checker/__init__.py b/qc_otx/checks/state_machine_checker/__init__.py index afce87b..b75f0f2 100644 --- a/qc_otx/checks/state_machine_checker/__init__.py +++ b/qc_otx/checks/state_machine_checker/__init__.py @@ -1,5 +1,3 @@ -from . import state_machine_constants as state_machine_constants -from . import state_machine_checker as state_machine_checker from . import no_procedure_realization as no_procedure_realization from . import mandatory_target_state as mandatory_target_state from . import no_target_state_for_completed_state as no_target_state_for_completed_state diff --git a/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py b/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py index 9a59f26..471b1eb 100644 --- a/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py +++ b/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py @@ -1,11 +1,19 @@ import logging -from qc_baselib import IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models, utils -from qc_otx.checks.state_machine_checker import state_machine_constants + +CHECKER_ID = ( + "check_asam_otx_state_machine_chk_006_distinguished_initial_and_completed_state" +) +CHECKER_DESCRIPTION = "The values of the mandatory initialState and optional completedState attributes shall be distinguished." +CHECKER_PRECONDITIONS = set() +RULE_UID = ( + "asam.net:otx:1.0.0:state_machine.chk_006.distinguished_initial_and_completed_state" +) def check_rule(checker_data: models.CheckerData) -> None: @@ -23,17 +31,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing distinguished_initial_and_completed_state check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="state_machine.chk_006.distinguished_initial_and_completed_state", - ) - tree = checker_data.input_file_xml_root nsmap = utils.get_namespace_map(tree) @@ -41,11 +38,24 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.error( 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' ) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) if state_machine_procedures is None: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -56,6 +66,12 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return smp_realisation = state_machine_procedure.xpath( @@ -67,6 +83,12 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.error( f"Invalid realisation found in current state machine procedure" ) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) return smp_realisation = smp_realisation[0] @@ -78,15 +100,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getelementpath(smp_realisation) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when initialState and completedState cannot be distinguished", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"State machine realisation cannot distinguish between initial and completed state", diff --git a/qc_otx/checks/state_machine_checker/mandatory_target_state.py b/qc_otx/checks/state_machine_checker/mandatory_target_state.py index 7c2ddd9..6f624c1 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_target_state.py +++ b/qc_otx/checks/state_machine_checker/mandatory_target_state.py @@ -1,11 +1,15 @@ import logging -from qc_baselib import IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models, utils -from qc_otx.checks.state_machine_checker import state_machine_constants + +CHECKER_ID = "check_asam_otx_state_machine_chk_002_mandatory_target_state" +CHECKER_DESCRIPTION = "Each state except the completed state shall have a target state." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:state_machine.chk_002.mandatory_target_state" def check_rule(checker_data: models.CheckerData) -> None: @@ -23,17 +27,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing mandatory_target_state check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="state_machine.chk_002.mandatory_target_state", - ) - tree = checker_data.input_file_xml_root nsmap = utils.get_namespace_map(tree) @@ -41,11 +34,25 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.error( 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' ) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) if state_machine_procedures is None: + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -56,6 +63,12 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return for sm_state in state_machine.states: @@ -66,15 +79,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getelementpath(sm_state.xml_element) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when a non completed state has no target state", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"State {sm_state.name} with id {sm_state.id} does not have any target state", diff --git a/qc_otx/checks/state_machine_checker/mandatory_transition.py b/qc_otx/checks/state_machine_checker/mandatory_transition.py index a0d8191..7a1d200 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_transition.py +++ b/qc_otx/checks/state_machine_checker/mandatory_transition.py @@ -1,11 +1,17 @@ import logging -from qc_baselib import IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models, utils -from qc_otx.checks.state_machine_checker import state_machine_constants + +CHECKER_ID = "check_asam_otx_state_machine_chk_005_mandatory_transition" +CHECKER_DESCRIPTION = ( + "Each state except the completed state shall have at least one transition." +) +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:state_machine.chk_005.mandatory_transition" def check_rule(checker_data: models.CheckerData) -> None: @@ -23,17 +29,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing mandatory_transition check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="state_machine.chk_005.mandatory_transition", - ) - tree = checker_data.input_file_xml_root nsmap = utils.get_namespace_map(tree) @@ -41,11 +36,25 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.error( 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' ) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) if state_machine_procedures is None: + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -56,6 +65,13 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return for sm_state in state_machine.states: @@ -64,15 +80,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getelementpath(sm_state.xml_element) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when a non completed state has no transition", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"State {sm_state.name} with id {sm_state.id} does not have any transition", diff --git a/qc_otx/checks/state_machine_checker/mandatory_trigger.py b/qc_otx/checks/state_machine_checker/mandatory_trigger.py index b8780a8..2924823 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_trigger.py +++ b/qc_otx/checks/state_machine_checker/mandatory_trigger.py @@ -1,11 +1,17 @@ import logging -from qc_baselib import IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models, utils -from qc_otx.checks.state_machine_checker import state_machine_constants + +CHECKER_ID = "check_asam_otx_state_machine_chk_004_mandatory_trigger" +CHECKER_DESCRIPTION = ( + "Each state except the completed state shall have at least one trigger." +) +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:state_machine.chk_004.mandatory_trigger" def check_rule(checker_data: models.CheckerData) -> None: @@ -23,17 +29,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing mandatory_trigger check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="state_machine.chk_004.mandatory_trigger", - ) - tree = checker_data.input_file_xml_root nsmap = utils.get_namespace_map(tree) @@ -41,11 +36,24 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.error( 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' ) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) if state_machine_procedures is None: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -56,6 +64,13 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return for sm_state in state_machine.states: @@ -64,15 +79,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getelementpath(sm_state.xml_element) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when a non completed state has no triggers", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"State {sm_state.name} with id {sm_state.id} does not have any trigger", diff --git a/qc_otx/checks/state_machine_checker/no_procedure_realization.py b/qc_otx/checks/state_machine_checker/no_procedure_realization.py index 6c9d740..294c7cf 100644 --- a/qc_otx/checks/state_machine_checker/no_procedure_realization.py +++ b/qc_otx/checks/state_machine_checker/no_procedure_realization.py @@ -1,11 +1,15 @@ import logging -from qc_baselib import IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models, utils -from qc_otx.checks.state_machine_checker import state_machine_constants + +CHECKER_ID = "check_asam_otx_state_machine_chk_001_no_procedure_realization" +CHECKER_DESCRIPTION = "A StateMachineProcedure shall not have a ProcedureRealisation." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:state_machine.chk_001.no_procedure_realization" def check_rule(checker_data: models.CheckerData) -> None: @@ -23,27 +27,29 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing no_procedure_realization check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="state_machine.chk_001.no_procedure_realization", - ) - tree = checker_data.input_file_xml_root nsmap = utils.get_namespace_map(tree) if "smp" not in nsmap: logging.error( 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' ) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) if state_machine_procedures is None: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -61,15 +67,15 @@ def check_rule(checker_data: models.CheckerData) -> None: procedure_realisation_xpath = tree.getpath(realisations[0]) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when StateMachineProcedure has a ProcedureRealisation", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"State machine {state_machine_procedure.get('id')} has a ProcedureRealisation at {procedure_realisation_xpath}", diff --git a/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py b/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py index c8480bc..4c07324 100644 --- a/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py +++ b/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py @@ -1,11 +1,17 @@ import logging -from qc_baselib import IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models, utils -from qc_otx.checks.state_machine_checker import state_machine_constants + +CHECKER_ID = "check_asam_otx_state_machine_chk_003_no_target_state_for_completed_state" +CHECKER_DESCRIPTION = "After finishing the completed state the procedure is finished and shall return to the caller. Therefore the completed state shall not have a target state." +CHECKER_PRECONDITIONS = set() +RULE_UID = ( + "asam.net:otx:1.0.0:state_machine.chk_003.no_target_state_for_completed_state" +) def check_rule(checker_data: models.CheckerData) -> None: @@ -24,17 +30,6 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing no_target_state_for_completed_state check") - issue_severity = IssueSeverity.WARNING - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="state_machine.chk_003.no_target_state_for_completed_state", - ) - tree = checker_data.input_file_xml_root nsmap = utils.get_namespace_map(tree) @@ -42,11 +37,24 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.error( 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' ) + + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) if state_machine_procedures is None: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -57,6 +65,12 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return completed_state = None @@ -66,6 +80,12 @@ def check_rule(checker_data: models.CheckerData) -> None: break if completed_state is None: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return has_issue = len(completed_state.target_state_ids) != 0 @@ -73,15 +93,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getelementpath(completed_state.xml_element) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when a completed state has a target state", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.WARNING, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Completed state {completed_state.name} with id {completed_state.id} has a target state but it should not", diff --git a/qc_otx/checks/state_machine_checker/state_machine_checker.py b/qc_otx/checks/state_machine_checker/state_machine_checker.py deleted file mode 100644 index 01efc87..0000000 --- a/qc_otx/checks/state_machine_checker/state_machine_checker.py +++ /dev/null @@ -1,51 +0,0 @@ -import logging - -from lxml import etree - -from qc_baselib import Configuration, Result, StatusType - -from qc_otx import constants -from qc_otx.checks import utils, models - -from qc_otx.checks.state_machine_checker import ( - state_machine_constants, - no_procedure_realization, - mandatory_target_state, - no_target_state_for_completed_state, - mandatory_transition, - mandatory_trigger, - distinguished_initial_and_completed_state, -) - - -def run_checks(checker_data: models.CheckerData) -> None: - logging.info("Executing state_machine checks") - - checker_data.result.register_checker( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, - description="Check if state_machine properties of input file are properly set", - summary="", - ) - - rule_list = [ - no_procedure_realization.check_rule, # Chk001 - mandatory_target_state.check_rule, # Chk002 - no_target_state_for_completed_state.check_rule, # Chk003 - mandatory_transition.check_rule, # Chk004 - mandatory_trigger.check_rule, # Chk005 - distinguished_initial_and_completed_state.check_rule, # Chk006 - ] - - for rule in rule_list: - rule(checker_data=checker_data) - - logging.info( - f"Issues found - {checker_data.result.get_checker_issue_count(checker_bundle_name=constants.BUNDLE_NAME, checker_id=state_machine_constants.CHECKER_ID)}" - ) - - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=state_machine_constants.CHECKER_ID, - status=StatusType.COMPLETED, - ) diff --git a/qc_otx/checks/state_machine_checker/state_machine_constants.py b/qc_otx/checks/state_machine_checker/state_machine_constants.py deleted file mode 100644 index 68c8fd2..0000000 --- a/qc_otx/checks/state_machine_checker/state_machine_constants.py +++ /dev/null @@ -1 +0,0 @@ -CHECKER_ID = "state_machine_otx" diff --git a/qc_otx/checks/utils.py b/qc_otx/checks/utils.py index 93aeae3..8c6f7e6 100644 --- a/qc_otx/checks/utils.py +++ b/qc_otx/checks/utils.py @@ -84,6 +84,17 @@ def compare_versions(version1: str, version2: str) -> int: v1_components = list(map(int, version1.split("."))) v2_components = list(map(int, version2.split("."))) + max_length = max(len(v1_components), len(v2_components)) + + # extend the length of the shorter components with zero + if len(v1_components) < max_length: + for _ in range(len(v1_components), max_length): + v1_components.append(0) + + if len(v2_components) < max_length: + for _ in range(len(v2_components), max_length): + v2_components.append(0) + # Compare each component until one is greater or they are equal for v1, v2 in zip(v1_components, v2_components): if v1 < v2: @@ -91,13 +102,7 @@ def compare_versions(version1: str, version2: str) -> int: elif v1 > v2: return 1 - # If all components are equal, compare based on length - if len(v1_components) < len(v2_components): - return -1 - elif len(v1_components) > len(v2_components): - return 1 - else: - return 0 + return 0 def get_state_machine(input_node: etree._Element, nsmap: Dict) -> models.StateMachine: diff --git a/qc_otx/checks/zip_file_checker/__init__.py b/qc_otx/checks/zip_file_checker/__init__.py index ede1608..6e8c088 100644 --- a/qc_otx/checks/zip_file_checker/__init__.py +++ b/qc_otx/checks/zip_file_checker/__init__.py @@ -1,4 +1,2 @@ -from . import zip_file_constants as zip_file_constants -from . import zip_file_checker as zip_file_checker from . import type_safe_zip_file as type_safe_zip_file from . import type_safe_unzip_file as type_safe_unzip_file diff --git a/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py b/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py index a258b81..c40fed0 100644 --- a/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py +++ b/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py @@ -1,11 +1,15 @@ import logging -from qc_baselib import IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.zip_file_checker import zip_file_constants + +CHECKER_ID = "check_asam_otx_zip_file_chk_001_type_safe_unzip_file" +CHECKER_DESCRIPTION = "In an UnZipFile action, the list described by ListTerm shall have a data type of ." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:zip_file.chk_001.type_safe_unzip_file" def check_rule(checker_data: models.CheckerData) -> None: @@ -24,22 +28,17 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing type_safe_unzip_file check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=zip_file_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="zip_file.chk_001.type_safe_unzip_file", - ) - tree = checker_data.input_file_xml_root root = tree.getroot() nsmap = {k: v for k, v in root.nsmap.items() if k is not None} if "xsi" not in nsmap or "zip" not in nsmap: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return unzip_nodes = tree.xpath("//*[@xsi:type='zip:UnZipFile']", namespaces=nsmap) @@ -79,15 +78,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getelementpath(current_list) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=zip_file_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when the list in an UnzipFile action does not contain type String", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=zip_file_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Unzip action does not contain any String type", diff --git a/qc_otx/checks/zip_file_checker/type_safe_zip_file.py b/qc_otx/checks/zip_file_checker/type_safe_zip_file.py index f12276e..01ee78f 100644 --- a/qc_otx/checks/zip_file_checker/type_safe_zip_file.py +++ b/qc_otx/checks/zip_file_checker/type_safe_zip_file.py @@ -1,11 +1,15 @@ import logging -from qc_baselib import IssueSeverity +from qc_baselib import IssueSeverity, StatusType from qc_otx import constants from qc_otx.checks import models -from qc_otx.checks.zip_file_checker import zip_file_constants + +CHECKER_ID = "check_asam_otx_zip_file_chk_002_type_safe_zip_file" +CHECKER_DESCRIPTION = "In a ZipFile action, the list described by ListTerm shall have a data type of ." +CHECKER_PRECONDITIONS = set() +RULE_UID = "asam.net:otx:1.0.0:zip_file.chk_002.type_safe_zip_file" def check_rule(checker_data: models.CheckerData) -> None: @@ -24,23 +28,19 @@ def check_rule(checker_data: models.CheckerData) -> None: """ logging.info("Executing correct_target_for_structure_element check") - issue_severity = IssueSeverity.ERROR - - rule_uid = checker_data.result.register_rule( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=zip_file_constants.CHECKER_ID, - emanating_entity="asam.net", - standard="otx", - definition_setting="1.0.0", - rule_full_name="zip_file.chk_002.type_safe_zip_file", - ) - tree = checker_data.input_file_xml_root root = tree.getroot() nsmap = {k: v for k, v in root.nsmap.items() if k is not None} if "xsi" not in nsmap or "zip" not in nsmap: + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=CHECKER_ID, + status=StatusType.SKIPPED, + ) + return + zip_nodes = tree.xpath("//*[@xsi:type='zip:ZipFile']", namespaces=nsmap) logging.debug(f"zip_nodes {zip_nodes}") @@ -79,15 +79,15 @@ def check_rule(checker_data: models.CheckerData) -> None: current_xpath = tree.getelementpath(current_list) issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=zip_file_constants.CHECKER_ID, + checker_id=CHECKER_ID, description="Issue flagging when the list in an ZipFile action does not contain type String", - level=issue_severity, - rule_uid=rule_uid, + level=IssueSeverity.ERROR, + rule_uid=RULE_UID, ) checker_data.result.add_xml_location( checker_bundle_name=constants.BUNDLE_NAME, - checker_id=zip_file_constants.CHECKER_ID, + checker_id=CHECKER_ID, issue_id=issue_id, xpath=current_xpath, description=f"Zip action does not contain any String type", diff --git a/qc_otx/checks/zip_file_checker/zip_file_checker.py b/qc_otx/checks/zip_file_checker/zip_file_checker.py deleted file mode 100644 index 6ff5fea..0000000 --- a/qc_otx/checks/zip_file_checker/zip_file_checker.py +++ /dev/null @@ -1,43 +0,0 @@ -import logging - -from lxml import etree - -from qc_baselib import Configuration, Result, StatusType - -from qc_otx import constants -from qc_otx.checks import utils, models - -from qc_otx.checks.zip_file_checker import ( - zip_file_constants, - type_safe_zip_file, - type_safe_unzip_file, -) - - -def run_checks(checker_data: models.CheckerData) -> None: - logging.info("Executing zip_file checks") - - checker_data.result.register_checker( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=zip_file_constants.CHECKER_ID, - description="Check if zip_file properties of input file are properly set", - summary="", - ) - - rule_list = [ - type_safe_zip_file.check_rule, # Chk001 - type_safe_unzip_file.check_rule, # Chk002 - ] - - for rule in rule_list: - rule(checker_data=checker_data) - - logging.info( - f"Issues found - {checker_data.result.get_checker_issue_count(checker_bundle_name=constants.BUNDLE_NAME, checker_id=zip_file_constants.CHECKER_ID)}" - ) - - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=zip_file_constants.CHECKER_ID, - status=StatusType.COMPLETED, - ) diff --git a/qc_otx/checks/zip_file_checker/zip_file_constants.py b/qc_otx/checks/zip_file_checker/zip_file_constants.py deleted file mode 100644 index 93117b7..0000000 --- a/qc_otx/checks/zip_file_checker/zip_file_constants.py +++ /dev/null @@ -1 +0,0 @@ -CHECKER_ID = "zip_file_otx" diff --git a/qc_otx/main.py b/qc_otx/main.py index 925dd8e..a8a8aab 100644 --- a/qc_otx/main.py +++ b/qc_otx/main.py @@ -2,14 +2,15 @@ import logging from datetime import datetime from lxml import etree +import types -from qc_baselib import Configuration, Result +from qc_baselib import Configuration, Result, StatusType from qc_baselib.models.common import ParamType from qc_otx import constants -from qc_otx.checks.core_checker import core_checker -from qc_otx.checks.data_type_checker import data_type_checker -from qc_otx.checks.zip_file_checker import zip_file_checker -from qc_otx.checks.state_machine_checker import state_machine_checker +from qc_otx.checks import core_checker +from qc_otx.checks import data_type_checker +from qc_otx.checks import zip_file_checker +from qc_otx.checks import state_machine_checker from qc_otx.checks import utils, models logging.basicConfig(format="%(asctime)s - %(message)s", level=logging.INFO) @@ -22,7 +23,6 @@ def args_entrypoint() -> argparse.Namespace: ) group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("-d", "--default_config", action="store_true") group.add_argument("-c", "--config_path") parser.add_argument("-g", "--generate_markdown", action="store_true") @@ -30,62 +30,185 @@ def args_entrypoint() -> argparse.Namespace: return parser.parse_args() -def main(): - args = args_entrypoint() +def execute_checker( + checker: types.ModuleType, + checker_data: models.CheckerData, + required_definition_setting: bool = True, +) -> None: + # Register checker + checker_data.result.register_checker( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=checker.CHECKER_ID, + description=checker.CHECKER_DESCRIPTION, + ) - logging.info("Initializing checks") + # Register rule uid + splitted_rule_uid = checker.RULE_UID.split(":") + if len(splitted_rule_uid) != 4: + raise RuntimeError(f"Invalid rule uid: {checker.RULE_UID}") + + checker_data.result.register_rule( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=checker.CHECKER_ID, + emanating_entity=splitted_rule_uid[0], + standard=splitted_rule_uid[1], + definition_setting=splitted_rule_uid[2], + rule_full_name=splitted_rule_uid[3], + ) - if args.default_config: - raise RuntimeError("Not implemented.") - else: - config = Configuration() - config.load_from_file(xml_file_path=args.config_path) - - result = Result() - result.register_checker_bundle( - name=constants.BUNDLE_NAME, - build_date=datetime.today().strftime("%Y-%m-%d"), - description="OTX checker bundle", - version=constants.BUNDLE_VERSION, - summary="", + # Check preconditions. If not satisfied then set status as SKIPPED and return + if not checker_data.result.all_checkers_completed_without_issue( + checker.CHECKER_PRECONDITIONS + ): + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=checker.CHECKER_ID, + status=StatusType.SKIPPED, ) - result.set_result_version(version=constants.BUNDLE_VERSION) - input_file_path = config.get_config_param("InputFile") - input_param = ParamType(name="InputFile", value=input_file_path) - result.get_checker_bundle_result(constants.BUNDLE_NAME).params.append( - input_param + return + + # Checker definition setting. If not satisfied then set status as SKIPPED and return + if required_definition_setting: + schema_version = checker_data.schema_version + definition_setting = splitted_rule_uid[2] + if ( + schema_version is None + or utils.compare_versions(schema_version, definition_setting) < 0 + ): + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=checker.CHECKER_ID, + status=StatusType.SKIPPED, + ) + + return + + # Execute checker + try: + checker.check_rule(checker_data) + + # If checker is not explicitly set as SKIPPED, then set it as COMPLETED + if ( + checker_data.result.get_checker_status(checker.CHECKER_ID) + != StatusType.SKIPPED + ): + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=checker.CHECKER_ID, + status=StatusType.COMPLETED, + ) + except Exception: + # If any exception occurs during the check, set the status as ERROR + checker_data.result.set_checker_status( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=checker.CHECKER_ID, + status=StatusType.ERROR, ) - root = etree.parse(config.get_config_param("InputFile")) - otx_schema_version = utils.get_standard_schema_version(root) - checker_data = models.CheckerData( - input_file_xml_root=root, - config=config, - result=result, - schema_version=otx_schema_version, - ) - # 1. Run basic checks - core_checker.run_checks(checker_data) +def run_checks(config: Configuration, result: Result) -> None: + root = etree.parse(config.get_config_param("InputFile")) + otx_schema_version = utils.get_standard_schema_version(root) + + checker_data = models.CheckerData( + input_file_xml_root=root, + config=config, + result=result, + schema_version=otx_schema_version, + ) + + # 1. Run basic checks + # Chk001 + execute_checker(core_checker.document_name_matches_filename, checker_data) + # Chk002 + execute_checker(core_checker.document_name_package_uniqueness, checker_data) + # Chk003 + execute_checker(core_checker.no_dead_import_links, checker_data) + # Chk004 + execute_checker(core_checker.no_unused_imports, checker_data) + # Chk005 + execute_checker(core_checker.no_use_of_undefined_import_prefixes, checker_data) + # Chk006 + execute_checker( + core_checker.match_of_imported_document_data_model_version, checker_data + ) + # Chk007 + execute_checker( + core_checker.have_specification_if_no_realisation_exists, checker_data + ) + # Chk008 + execute_checker(core_checker.public_main_procedure, checker_data) + # Chk009 + execute_checker(core_checker.mandatory_constant_initialization, checker_data) + # Chk010 + execute_checker(core_checker.unique_node_names, checker_data) + + # 2. Run data type checks + # Chk001 + execute_checker(data_type_checker.accessing_structure_elements, checker_data) + # Chk008 + execute_checker( + data_type_checker.correct_target_for_structure_element, checker_data + ) - # 2. Run data type checks - data_type_checker.run_checks(checker_data) + # 3. Run zip file checks + # Chk001 + execute_checker(zip_file_checker.type_safe_zip_file, checker_data) + # Chk002 + execute_checker(zip_file_checker.type_safe_unzip_file, checker_data) + + # 4. Run state machine checks + # Chk001 + execute_checker(state_machine_checker.no_procedure_realization, checker_data) + # Chk002 + execute_checker(state_machine_checker.mandatory_target_state, checker_data) + # Chk003 + execute_checker( + state_machine_checker.no_target_state_for_completed_state, checker_data + ) + # Chk004 + execute_checker(state_machine_checker.mandatory_transition, checker_data) + # Chk005 + execute_checker(state_machine_checker.mandatory_trigger, checker_data) + # Chk006 + execute_checker( + state_machine_checker.distinguished_initial_and_completed_state, checker_data + ) - # 3. Run zip file checks - zip_file_checker.run_checks(checker_data) - # 4. Run state machine checks - state_machine_checker.run_checks(checker_data) +def main(): + args = args_entrypoint() - result.write_to_file( - config.get_checker_bundle_param( - checker_bundle_name=constants.BUNDLE_NAME, param_name="resultFile" - ) + logging.info("Initializing checks") + + config = Configuration() + config.load_from_file(xml_file_path=args.config_path) + + result = Result() + result.register_checker_bundle( + name=constants.BUNDLE_NAME, + build_date=datetime.today().strftime("%Y-%m-%d"), + description="OTX checker bundle", + version=constants.BUNDLE_VERSION, + summary="", + ) + result.set_result_version(version=constants.BUNDLE_VERSION) + + input_file_path = config.get_config_param("InputFile") + input_param = ParamType(name="InputFile", value=input_file_path) + result.get_checker_bundle_result(constants.BUNDLE_NAME).params.append(input_param) + + run_checks(config, result) + + result.write_to_file( + config.get_checker_bundle_param( + checker_bundle_name=constants.BUNDLE_NAME, param_name="resultFile" ) + ) - if args.generate_markdown: - result.write_markdown_doc("generated_checker_bundle_doc.md") + if args.generate_markdown: + result.write_markdown_doc("generated_checker_bundle_doc.md") logging.info("Done") diff --git a/tests/test_core_checks.py b/tests/test_core_checks.py index ccaff5c..9339595 100644 --- a/tests/test_core_checks.py +++ b/tests/test_core_checks.py @@ -1,9 +1,8 @@ import os import pytest import test_utils -from qc_otx import constants -from qc_otx.checks.core_checker import core_constants -from qc_baselib import Result, IssueSeverity +from qc_baselib import Result, IssueSeverity, StatusType +from qc_otx.checks import core_checker def test_chk001_positive( @@ -20,6 +19,13 @@ def test_chk001_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.document_name_matches_filename.CHECKER_ID + ) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -46,6 +52,13 @@ def test_chk001_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.document_name_matches_filename.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_001.document_name_matches_filename" ) @@ -69,6 +82,13 @@ def test_chk002_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.document_name_package_uniqueness.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_002.document_name_package_uniqueness" ) @@ -90,6 +110,13 @@ def test_chk002_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.document_name_package_uniqueness.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_002.document_name_package_uniqueness" ) @@ -113,6 +140,11 @@ def test_chk003_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.no_dead_import_links.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_003.no_dead_import_links" ) @@ -134,6 +166,11 @@ def test_chk003_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.no_dead_import_links.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_003.no_dead_import_links" ) @@ -157,6 +194,11 @@ def test_chk004_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.no_unused_imports.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_004.no_unused_imports" ) @@ -178,6 +220,11 @@ def test_chk004_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.no_unused_imports.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_004.no_unused_imports" ) @@ -201,6 +248,13 @@ def test_chk005_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.no_use_of_undefined_import_prefixes.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_005.no_use_of_undefined_import_prefixes" ) @@ -222,6 +276,13 @@ def test_chk005_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.no_use_of_undefined_import_prefixes.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_005.no_use_of_undefined_import_prefixes" ) @@ -246,6 +307,13 @@ def test_chk006_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.match_of_imported_document_data_model_version.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_006.match_of_imported_document_data_model_version" ) @@ -267,6 +335,13 @@ def test_chk006_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.match_of_imported_document_data_model_version.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_006.match_of_imported_document_data_model_version" ) @@ -291,6 +366,13 @@ def test_chk007_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.have_specification_if_no_realisation_exists.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_007.have_specification_if_no_realisation_exists" ) @@ -312,6 +394,13 @@ def test_chk007_positive_no_specification( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.have_specification_if_no_realisation_exists.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_007.have_specification_if_no_realisation_exists" ) @@ -333,6 +422,13 @@ def test_chk007_positive_no_realisation( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.have_specification_if_no_realisation_exists.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_007.have_specification_if_no_realisation_exists" ) @@ -354,6 +450,13 @@ def test_chk007_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.have_specification_if_no_realisation_exists.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_007.have_specification_if_no_realisation_exists" ) @@ -377,6 +480,13 @@ def test_chk007_negative_no_specification( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.have_specification_if_no_realisation_exists.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_007.have_specification_if_no_realisation_exists" ) @@ -400,6 +510,13 @@ def test_chk007_negative_empty_string( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.have_specification_if_no_realisation_exists.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_007.have_specification_if_no_realisation_exists" ) @@ -423,6 +540,11 @@ def test_chk008_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.public_main_procedure.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" ) @@ -444,6 +566,11 @@ def test_chk008_positive_two_mains( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.public_main_procedure.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" ) @@ -465,6 +592,11 @@ def test_chk008_positive_no_main( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.public_main_procedure.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" ) @@ -486,6 +618,11 @@ def test_chk008_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.public_main_procedure.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" ) @@ -509,6 +646,11 @@ def test_chk008_negative_two_mains( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.public_main_procedure.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" ) @@ -532,6 +674,11 @@ def test_chk008_negative_no_visibility( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.public_main_procedure.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" ) @@ -555,6 +702,13 @@ def test_chk009_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.mandatory_constant_initialization.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" ) @@ -576,6 +730,13 @@ def test_chk009_positive_multiple( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.mandatory_constant_initialization.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" ) @@ -597,6 +758,13 @@ def test_chk009_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.mandatory_constant_initialization.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" ) @@ -620,6 +788,13 @@ def test_chk009_negative_multiple( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.mandatory_constant_initialization.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" ) @@ -643,6 +818,13 @@ def test_chk009_negative_multiple_errors( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + core_checker.mandatory_constant_initialization.CHECKER_ID + ) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" ) @@ -667,6 +849,11 @@ def test_chk010_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.unique_node_names.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_010.unique_node_names" ) @@ -688,6 +875,11 @@ def test_chk010_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(core_checker.unique_node_names.CHECKER_ID) + == StatusType.COMPLETED + ) + core_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:core.chk_010.unique_node_names" ) diff --git a/tests/test_data_type_checks.py b/tests/test_data_type_checks.py index da1ba8a..9f0e97c 100644 --- a/tests/test_data_type_checks.py +++ b/tests/test_data_type_checks.py @@ -1,9 +1,8 @@ import os import pytest import test_utils -from qc_otx import constants -from qc_otx.checks.core_checker import core_constants -from qc_baselib import Result, IssueSeverity +from qc_baselib import Result, IssueSeverity, StatusType +from qc_otx.checks import data_type_checker def test_chk001_positive( @@ -20,6 +19,13 @@ def test_chk001_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + data_type_checker.accessing_structure_elements.CHECKER_ID + ) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -46,6 +52,13 @@ def test_chk001_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + data_type_checker.accessing_structure_elements.CHECKER_ID + ) + == StatusType.COMPLETED + ) + data_type_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:data_type.chk_001.accessing_structure_elements" ) @@ -69,6 +82,13 @@ def test_chk008_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + data_type_checker.correct_target_for_structure_element.CHECKER_ID + ) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -95,6 +115,13 @@ def test_chk008_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + data_type_checker.correct_target_for_structure_element.CHECKER_ID + ) + == StatusType.COMPLETED + ) + data_type_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:data_type.chk_008.correct_target_for_structure_element" ) diff --git a/tests/test_state_machine_checks.py b/tests/test_state_machine_checks.py index 550b40b..83bd9b5 100644 --- a/tests/test_state_machine_checks.py +++ b/tests/test_state_machine_checks.py @@ -1,9 +1,8 @@ import os import pytest import test_utils -from qc_otx import constants -from qc_otx.checks.core_checker import core_constants -from qc_baselib import Result, IssueSeverity +from qc_baselib import Result, IssueSeverity, StatusType +from qc_otx.checks import state_machine_checker def test_chk001_positive( @@ -20,6 +19,13 @@ def test_chk001_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.no_procedure_realization.CHECKER_ID + ) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -46,6 +52,13 @@ def test_chk001_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.no_procedure_realization.CHECKER_ID + ) + == StatusType.COMPLETED + ) + state_machine_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:state_machine.chk_001.no_procedure_realization" ) @@ -69,6 +82,13 @@ def test_chk002_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.mandatory_target_state.CHECKER_ID + ) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -95,6 +115,13 @@ def test_chk002_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.mandatory_target_state.CHECKER_ID + ) + == StatusType.COMPLETED + ) + state_machine_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:state_machine.chk_002.mandatory_target_state" ) @@ -118,6 +145,13 @@ def test_chk003_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.no_target_state_for_completed_state.CHECKER_ID + ) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -144,6 +178,13 @@ def test_chk003_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.no_target_state_for_completed_state.CHECKER_ID + ) + == StatusType.COMPLETED + ) + state_machine_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:state_machine.chk_003.no_target_state_for_completed_state" ) @@ -167,6 +208,11 @@ def test_chk004_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(state_machine_checker.mandatory_trigger.CHECKER_ID) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -193,6 +239,11 @@ def test_chk004_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(state_machine_checker.mandatory_trigger.CHECKER_ID) + == StatusType.COMPLETED + ) + state_machine_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:state_machine.chk_004.mandatory_trigger" ) @@ -216,6 +267,11 @@ def test_chk005_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(state_machine_checker.mandatory_transition.CHECKER_ID) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -242,6 +298,11 @@ def test_chk005_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(state_machine_checker.mandatory_transition.CHECKER_ID) + == StatusType.COMPLETED + ) + state_machine_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:state_machine.chk_005.mandatory_transition" ) @@ -265,6 +326,13 @@ def test_chk006_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.distinguished_initial_and_completed_state.CHECKER_ID + ) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -291,6 +359,13 @@ def test_chk006_positive_no_completed( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.distinguished_initial_and_completed_state.CHECKER_ID + ) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -317,6 +392,13 @@ def test_chk006_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status( + state_machine_checker.distinguished_initial_and_completed_state.CHECKER_ID + ) + == StatusType.COMPLETED + ) + state_machine_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:state_machine.chk_006.distinguished_initial_and_completed_state" ) diff --git a/tests/test_utils.py b/tests/test_utils.py index a5196ae..c1b5f66 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,6 @@ import os import sys import pytest -from typing import List import qc_otx.main as main from qc_otx import constants, checks from qc_baselib import Configuration, Result diff --git a/tests/test_zip_file_checks.py b/tests/test_zip_file_checks.py index 576f53a..a793576 100644 --- a/tests/test_zip_file_checks.py +++ b/tests/test_zip_file_checks.py @@ -1,9 +1,8 @@ import os import pytest import test_utils -from qc_otx import constants -from qc_otx.checks.core_checker import core_constants -from qc_baselib import Result, IssueSeverity +from qc_baselib import Result, IssueSeverity, StatusType +from qc_otx.checks import zip_file_checker def test_chk001_positive( @@ -20,6 +19,11 @@ def test_chk001_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(zip_file_checker.type_safe_unzip_file.CHECKER_ID) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -46,6 +50,11 @@ def test_chk001_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(zip_file_checker.type_safe_unzip_file.CHECKER_ID) + == StatusType.COMPLETED + ) + zip_file_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:zip_file.chk_001.type_safe_unzip_file" ) @@ -69,6 +78,11 @@ def test_chk002_positive( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(zip_file_checker.type_safe_zip_file.CHECKER_ID) + == StatusType.COMPLETED + ) + assert ( len( result.get_issues_by_rule_uid( @@ -95,6 +109,11 @@ def test_chk002_negative( result = Result() result.load_from_file(test_utils.REPORT_FILE_PATH) + assert ( + result.get_checker_status(zip_file_checker.type_safe_zip_file.CHECKER_ID) + == StatusType.COMPLETED + ) + zip_file_issues = result.get_issues_by_rule_uid( "asam.net:otx:1.0.0:zip_file.chk_002.type_safe_zip_file" ) From edf97737eff3ffdfade57c61bb5c7f8eea747a2c Mon Sep 17 00:00:00 2001 From: romanodanilo <62891297+romanodanilo@users.noreply.github.com> Date: Tue, 17 Sep 2024 11:12:54 +0200 Subject: [PATCH 2/5] Update issue description (#31) Signed-off-by: romanodanilo Signed-off-by: romanodanilo <62891297+romanodanilo@users.noreply.github.com> --- qc_otx/checks/core_checker/document_name_matches_filename.py | 2 +- .../checks/core_checker/document_name_package_uniqueness.py | 2 +- .../have_specification_if_no_realisation_exists.py | 2 +- .../checks/core_checker/mandatory_constant_initialization.py | 2 +- .../match_of_imported_document_data_model_version.py | 2 +- qc_otx/checks/core_checker/no_dead_import_links.py | 2 +- qc_otx/checks/core_checker/no_unused_imports.py | 2 +- .../core_checker/no_use_of_undefined_import_prefixes.py | 2 +- qc_otx/checks/core_checker/public_main_procedure.py | 2 +- qc_otx/checks/core_checker/unique_node_names.py | 2 +- .../checks/data_type_checker/accessing_structure_elements.py | 2 +- .../data_type_checker/correct_target_for_structure_element.py | 2 +- .../distinguished_initial_and_completed_state.py | 2 +- qc_otx/checks/state_machine_checker/mandatory_target_state.py | 4 ++-- qc_otx/checks/state_machine_checker/mandatory_transition.py | 2 +- qc_otx/checks/state_machine_checker/mandatory_trigger.py | 2 +- .../checks/state_machine_checker/no_procedure_realization.py | 2 +- .../no_target_state_for_completed_state.py | 2 +- qc_otx/checks/zip_file_checker/type_safe_unzip_file.py | 2 +- qc_otx/checks/zip_file_checker/type_safe_zip_file.py | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/qc_otx/checks/core_checker/document_name_matches_filename.py b/qc_otx/checks/core_checker/document_name_matches_filename.py index b393960..9bbf42f 100644 --- a/qc_otx/checks/core_checker/document_name_matches_filename.py +++ b/qc_otx/checks/core_checker/document_name_matches_filename.py @@ -51,7 +51,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when document name does not match file name", + description="Document name not matching file name", level=IssueSeverity.WARNING, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/document_name_package_uniqueness.py b/qc_otx/checks/core_checker/document_name_package_uniqueness.py index 988bb26..cab81c2 100644 --- a/qc_otx/checks/core_checker/document_name_package_uniqueness.py +++ b/qc_otx/checks/core_checker/document_name_package_uniqueness.py @@ -139,7 +139,7 @@ def check_rule(checker_data: models.CheckerData) -> None: checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when otx name is reused in the same package", + description=" attribute name re-used in the same package", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/have_specification_if_no_realisation_exists.py b/qc_otx/checks/core_checker/have_specification_if_no_realisation_exists.py index 2eec8a5..abfbaf4 100644 --- a/qc_otx/checks/core_checker/have_specification_if_no_realisation_exists.py +++ b/qc_otx/checks/core_checker/have_specification_if_no_realisation_exists.py @@ -61,7 +61,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue to check if empty realisation have content in specification", + description="Empty realisation has content in specification", level=IssueSeverity.WARNING, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/mandatory_constant_initialization.py b/qc_otx/checks/core_checker/mandatory_constant_initialization.py index aefc211..b9465e7 100644 --- a/qc_otx/checks/core_checker/mandatory_constant_initialization.py +++ b/qc_otx/checks/core_checker/mandatory_constant_initialization.py @@ -37,7 +37,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when a constant is not initialized", + description="Constant declaration without initialization", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py b/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py index cb0e243..2b68b72 100644 --- a/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py +++ b/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py @@ -91,7 +91,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when data model version of imported document is different than the one in current document", + description="Imported document data model version is different than the one in the current document", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/no_dead_import_links.py b/qc_otx/checks/core_checker/no_dead_import_links.py index aac89c4..a635652 100644 --- a/qc_otx/checks/core_checker/no_dead_import_links.py +++ b/qc_otx/checks/core_checker/no_dead_import_links.py @@ -52,7 +52,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when an imported otx document does not exists at specified package", + description="Imported otx document does not exists at specified package", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/no_unused_imports.py b/qc_otx/checks/core_checker/no_unused_imports.py index 02339f1..c8f1156 100644 --- a/qc_otx/checks/core_checker/no_unused_imports.py +++ b/qc_otx/checks/core_checker/no_unused_imports.py @@ -49,7 +49,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when an imported otx document is never used in the current otx", + description="Imported otx is never used in the current document", level=IssueSeverity.WARNING, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py b/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py index 8881fbb..8afc899 100644 --- a/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py +++ b/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py @@ -68,7 +68,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when prefix definition does not exists in an import element", + description="Prefix definition does not exists in an element", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/public_main_procedure.py b/qc_otx/checks/core_checker/public_main_procedure.py index d10a0a0..2094a94 100644 --- a/qc_otx/checks/core_checker/public_main_procedure.py +++ b/qc_otx/checks/core_checker/public_main_procedure.py @@ -40,7 +40,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when procedure called main has not PUBLIC visibility", + description="Procedure called main has not PUBLIC visibility", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/core_checker/unique_node_names.py b/qc_otx/checks/core_checker/unique_node_names.py index 899749b..7cd9c9b 100644 --- a/qc_otx/checks/core_checker/unique_node_names.py +++ b/qc_otx/checks/core_checker/unique_node_names.py @@ -64,7 +64,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when nodes with same attribute name are found in a procedure", + description="Nodes with same attribute name found in a procedure", level=IssueSeverity.WARNING, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/data_type_checker/accessing_structure_elements.py b/qc_otx/checks/data_type_checker/accessing_structure_elements.py index 4a9daa0..5d0dbdd 100644 --- a/qc_otx/checks/data_type_checker/accessing_structure_elements.py +++ b/qc_otx/checks/data_type_checker/accessing_structure_elements.py @@ -82,7 +82,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when StepByName node accessing invalid fields", + description="StepByName node accessing invalid fields", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/data_type_checker/correct_target_for_structure_element.py b/qc_otx/checks/data_type_checker/correct_target_for_structure_element.py index 44839a5..b6a66c8 100644 --- a/qc_otx/checks/data_type_checker/correct_target_for_structure_element.py +++ b/qc_otx/checks/data_type_checker/correct_target_for_structure_element.py @@ -80,7 +80,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when invalid names is used in accessing structure element", + description="Invalid names used while accessing structure element", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py b/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py index 471b1eb..bfffc8d 100644 --- a/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py +++ b/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py @@ -101,7 +101,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when initialState and completedState cannot be distinguished", + description="initialState and completedState cannot be distinguished", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/state_machine_checker/mandatory_target_state.py b/qc_otx/checks/state_machine_checker/mandatory_target_state.py index 6f624c1..8fa718b 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_target_state.py +++ b/qc_otx/checks/state_machine_checker/mandatory_target_state.py @@ -68,7 +68,7 @@ def check_rule(checker_data: models.CheckerData) -> None: checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) - + return for sm_state in state_machine.states: @@ -80,7 +80,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when a non completed state has no target state", + description="Non-completed state has no target state", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/state_machine_checker/mandatory_transition.py b/qc_otx/checks/state_machine_checker/mandatory_transition.py index 7a1d200..f4d4b4d 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_transition.py +++ b/qc_otx/checks/state_machine_checker/mandatory_transition.py @@ -81,7 +81,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when a non completed state has no transition", + description="Non completed state has no transition", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/state_machine_checker/mandatory_trigger.py b/qc_otx/checks/state_machine_checker/mandatory_trigger.py index 2924823..b3170de 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_trigger.py +++ b/qc_otx/checks/state_machine_checker/mandatory_trigger.py @@ -80,7 +80,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when a non completed state has no triggers", + description="Non completed state has no triggers", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/state_machine_checker/no_procedure_realization.py b/qc_otx/checks/state_machine_checker/no_procedure_realization.py index 294c7cf..1739c65 100644 --- a/qc_otx/checks/state_machine_checker/no_procedure_realization.py +++ b/qc_otx/checks/state_machine_checker/no_procedure_realization.py @@ -68,7 +68,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when StateMachineProcedure has a ProcedureRealisation", + description="StateMachineProcedure has a ProcedureRealisation", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py b/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py index 4c07324..306f85b 100644 --- a/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py +++ b/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py @@ -94,7 +94,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when a completed state has a target state", + description="completed state has a target state", level=IssueSeverity.WARNING, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py b/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py index c40fed0..4f3a022 100644 --- a/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py +++ b/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py @@ -79,7 +79,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when the list in an UnzipFile action does not contain type String", + description="UnzipFile action specifies a List not String typed", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) diff --git a/qc_otx/checks/zip_file_checker/type_safe_zip_file.py b/qc_otx/checks/zip_file_checker/type_safe_zip_file.py index 01ee78f..7c4f985 100644 --- a/qc_otx/checks/zip_file_checker/type_safe_zip_file.py +++ b/qc_otx/checks/zip_file_checker/type_safe_zip_file.py @@ -80,7 +80,7 @@ def check_rule(checker_data: models.CheckerData) -> None: issue_id = checker_data.result.register_issue( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, - description="Issue flagging when the list in an ZipFile action does not contain type String", + description="ZipFile action specifies a List not String typed", level=IssueSeverity.ERROR, rule_uid=RULE_UID, ) From 7116f64683d44bc2ffe32e924699cf03f620c181 Mon Sep 17 00:00:00 2001 From: Hoang Tung Dinh Date: Tue, 17 Sep 2024 11:52:25 +0200 Subject: [PATCH 3/5] Add summary to result file and update state machine checks (#32) Signed-off-by: hoangtungdinh <11166240+hoangtungdinh@users.noreply.github.com> --- poetry.lock | 2 +- .../document_name_matches_filename.py | 8 +++-- .../document_name_package_uniqueness.py | 25 +++++++++++---- ...of_imported_document_data_model_version.py | 18 +++++++---- .../no_use_of_undefined_import_prefixes.py | 8 +++-- ...stinguished_initial_and_completed_state.py | 31 ++++++++---------- .../mandatory_target_state.py | 25 ++++++++------- .../mandatory_transition.py | 26 +++++++-------- .../mandatory_trigger.py | 25 ++++++++------- .../no_procedure_realization.py | 16 +++++++--- .../no_target_state_for_completed_state.py | 32 ++++++++----------- .../zip_file_checker/type_safe_unzip_file.py | 7 ++++ .../zip_file_checker/type_safe_zip_file.py | 6 ++++ qc_otx/main.py | 21 ++++++++++-- 14 files changed, 154 insertions(+), 96 deletions(-) diff --git a/poetry.lock b/poetry.lock index 61953b6..54a71a0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -29,7 +29,7 @@ pydantic-xml = "^2.11.0" type = "git" url = "https://github.com/asam-ev/qc-baselib-py.git" reference = "develop" -resolved_reference = "f7ea664805bcce456ebd0ede93c852dd389c1944" +resolved_reference = "8ed36cb58c8994b9674f7c6ea74992dacb65bdaf" [[package]] name = "black" diff --git a/qc_otx/checks/core_checker/document_name_matches_filename.py b/qc_otx/checks/core_checker/document_name_matches_filename.py index 9bbf42f..86f3084 100644 --- a/qc_otx/checks/core_checker/document_name_matches_filename.py +++ b/qc_otx/checks/core_checker/document_name_matches_filename.py @@ -30,14 +30,18 @@ def check_rule(checker_data: models.CheckerData) -> None: root_attrib = root.getroot().attrib if "name" not in root_attrib: - logging.error("No name attribute find in otx root node. Abort...") - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + "No name attribute in otx root node. Skip the check.", + ) + return document_name = root_attrib["name"] diff --git a/qc_otx/checks/core_checker/document_name_package_uniqueness.py b/qc_otx/checks/core_checker/document_name_package_uniqueness.py index cab81c2..95a4e04 100644 --- a/qc_otx/checks/core_checker/document_name_package_uniqueness.py +++ b/qc_otx/checks/core_checker/document_name_package_uniqueness.py @@ -61,26 +61,34 @@ def check_rule(checker_data: models.CheckerData) -> None: document_name = root.get("name") if document_name is None: - logging.error("No name attribute find in otx root node. Abort...") - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + "No name attribute in otx root node. Skip the check.", + ) + return package_name = root.get("package") if package_name is None: - logging.error("No package attribute find in otx root node. Abort...") - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + "No package attribute in otx root node. Skip the check.", + ) + return document_package_dot_name = package_name + "." + document_name @@ -110,9 +118,6 @@ def check_rule(checker_data: models.CheckerData) -> None: package_root = os.path.join(package_root, package_splits[0]) if not os.path.exists(package_root): - logging.error( - f"Error in setting package root {package_root}. Folder not found. Abort..." - ) os.chdir(previous_wd) checker_data.result.set_checker_status( @@ -121,6 +126,12 @@ def check_rule(checker_data: models.CheckerData) -> None: status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"The package root folder {package_root} does not exist. Skip the check.", + ) + return # Collect all otx file path from package root package_otx_files = find_otx_files(package_root) diff --git a/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py b/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py index 2b68b72..0f46747 100644 --- a/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py +++ b/qc_otx/checks/core_checker/match_of_imported_document_data_model_version.py @@ -35,16 +35,18 @@ def check_rule(checker_data: models.CheckerData) -> None: source_data_model_version = utils.get_data_model_version(root) if source_data_model_version is None: - logging.error( - "xmlns version not found in current document root. Skipping check.." - ) - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"xmlns version not found in current document root. Skip the check.", + ) + return logging.debug(f"source_data_model_version: {source_data_model_version}") @@ -52,14 +54,18 @@ def check_rule(checker_data: models.CheckerData) -> None: import_nodes = root.findall(".//import", namespaces=root.nsmap) if import_nodes is None: - logging.error("No import nodes found. Skipping check..") - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"No import nodes found. Skip the check.", + ) + return # Store previous working directory and move to config path dir for relative package paths diff --git a/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py b/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py index 8afc899..025233c 100644 --- a/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py +++ b/qc_otx/checks/core_checker/no_use_of_undefined_import_prefixes.py @@ -35,14 +35,18 @@ def check_rule(checker_data: models.CheckerData) -> None: import_nodes = root.findall(".//import", namespaces=root.nsmap) if import_nodes is None: - logging.error("No import nodes found. Skipping check..") - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"No import nodes found. Skip the check.", + ) + return import_prefixes = [x.get("prefix") for x in import_nodes] diff --git a/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py b/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py index bfffc8d..6aa93f3 100644 --- a/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py +++ b/qc_otx/checks/state_machine_checker/distinguished_initial_and_completed_state.py @@ -45,6 +45,12 @@ def check_rule(checker_data: models.CheckerData) -> None: status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"No state machine procedure prefix 'smp' found in document namespaces. Skip the check.", + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) @@ -56,6 +62,12 @@ def check_rule(checker_data: models.CheckerData) -> None: status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"State machine procedures not found. Skip the check.", + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -66,13 +78,7 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=CHECKER_ID, - status=StatusType.SKIPPED, - ) - - return + continue smp_realisation = state_machine_procedure.xpath( "./smp:realisation", namespaces=nsmap @@ -80,16 +86,7 @@ def check_rule(checker_data: models.CheckerData) -> None: logging.debug(f"smp_realisation: {smp_realisation}") if smp_realisation is None or len(smp_realisation) != 1: - logging.error( - f"Invalid realisation found in current state machine procedure" - ) - - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=CHECKER_ID, - status=StatusType.SKIPPED, - ) - return + continue smp_realisation = smp_realisation[0] diff --git a/qc_otx/checks/state_machine_checker/mandatory_target_state.py b/qc_otx/checks/state_machine_checker/mandatory_target_state.py index 8fa718b..3b2904e 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_target_state.py +++ b/qc_otx/checks/state_machine_checker/mandatory_target_state.py @@ -31,28 +31,35 @@ def check_rule(checker_data: models.CheckerData) -> None: nsmap = utils.get_namespace_map(tree) if "smp" not in nsmap: - logging.error( - 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' - ) - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"No state machine procedure prefix 'smp' found in document namespaces. Skip the check.", + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) if state_machine_procedures is None: - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"State machine procedures not found. Skip the check.", + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -63,13 +70,7 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=CHECKER_ID, - status=StatusType.SKIPPED, - ) - - return + continue for sm_state in state_machine.states: has_issue = ( diff --git a/qc_otx/checks/state_machine_checker/mandatory_transition.py b/qc_otx/checks/state_machine_checker/mandatory_transition.py index f4d4b4d..f646b11 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_transition.py +++ b/qc_otx/checks/state_machine_checker/mandatory_transition.py @@ -33,28 +33,35 @@ def check_rule(checker_data: models.CheckerData) -> None: nsmap = utils.get_namespace_map(tree) if "smp" not in nsmap: - logging.error( - 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' - ) - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"No state machine procedure prefix 'smp' found in document namespaces. Skip the check.", + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) if state_machine_procedures is None: - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"State machine procedures not found. Skip the check.", + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -65,14 +72,7 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: - - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=CHECKER_ID, - status=StatusType.SKIPPED, - ) - - return + continue for sm_state in state_machine.states: has_issue = not sm_state.is_completed and len(sm_state.transitions) == 0 diff --git a/qc_otx/checks/state_machine_checker/mandatory_trigger.py b/qc_otx/checks/state_machine_checker/mandatory_trigger.py index b3170de..880785e 100644 --- a/qc_otx/checks/state_machine_checker/mandatory_trigger.py +++ b/qc_otx/checks/state_machine_checker/mandatory_trigger.py @@ -33,16 +33,18 @@ def check_rule(checker_data: models.CheckerData) -> None: nsmap = utils.get_namespace_map(tree) if "smp" not in nsmap: - logging.error( - 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' - ) - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"No state machine procedure prefix 'smp' found in document namespaces. Skip the check.", + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) @@ -54,6 +56,12 @@ def check_rule(checker_data: models.CheckerData) -> None: status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"State machine procedures not found. Skip the check.", + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -64,14 +72,7 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: - - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=CHECKER_ID, - status=StatusType.SKIPPED, - ) - - return + continue for sm_state in state_machine.states: has_issue = not sm_state.is_completed and len(sm_state.triggers) == 0 diff --git a/qc_otx/checks/state_machine_checker/no_procedure_realization.py b/qc_otx/checks/state_machine_checker/no_procedure_realization.py index 1739c65..9955f62 100644 --- a/qc_otx/checks/state_machine_checker/no_procedure_realization.py +++ b/qc_otx/checks/state_machine_checker/no_procedure_realization.py @@ -30,16 +30,18 @@ def check_rule(checker_data: models.CheckerData) -> None: tree = checker_data.input_file_xml_root nsmap = utils.get_namespace_map(tree) if "smp" not in nsmap: - logging.error( - 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' - ) - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"No state machine procedure prefix 'smp' found in document namespaces. Skip the check.", + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) @@ -50,6 +52,12 @@ def check_rule(checker_data: models.CheckerData) -> None: status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"State machine procedures not found. Skip the check.", + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") diff --git a/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py b/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py index 306f85b..e92f45a 100644 --- a/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py +++ b/qc_otx/checks/state_machine_checker/no_target_state_for_completed_state.py @@ -34,16 +34,18 @@ def check_rule(checker_data: models.CheckerData) -> None: nsmap = utils.get_namespace_map(tree) if "smp" not in nsmap: - logging.error( - 'No state machine procedure prefix "smp" found in document namespaces. Abort state machine procedure checks...' - ) - checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, checker_id=CHECKER_ID, status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"No state machine procedure prefix 'smp' found in document namespaces. Skip the check.", + ) + return state_machine_procedures = utils.get_state_machine_procedures(tree, nsmap) @@ -55,6 +57,12 @@ def check_rule(checker_data: models.CheckerData) -> None: status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"State machine procedures not found. Skip the check.", + ) + return logging.debug(f"state_machine_procedures: {state_machine_procedures}") @@ -65,13 +73,7 @@ def check_rule(checker_data: models.CheckerData) -> None: state_machine = utils.get_state_machine(state_machine_procedure, nsmap) if state_machine is None: - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=CHECKER_ID, - status=StatusType.SKIPPED, - ) - - return + continue completed_state = None for sm_state in state_machine.states: @@ -80,13 +82,7 @@ def check_rule(checker_data: models.CheckerData) -> None: break if completed_state is None: - checker_data.result.set_checker_status( - checker_bundle_name=constants.BUNDLE_NAME, - checker_id=CHECKER_ID, - status=StatusType.SKIPPED, - ) - - return + continue has_issue = len(completed_state.target_state_ids) != 0 if has_issue: diff --git a/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py b/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py index 4f3a022..eaa7e43 100644 --- a/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py +++ b/qc_otx/checks/zip_file_checker/type_safe_unzip_file.py @@ -39,7 +39,14 @@ def check_rule(checker_data: models.CheckerData) -> None: status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"xsi is not in nsmap or zip is not in nsmap. Skip the check.", + ) + return + unzip_nodes = tree.xpath("//*[@xsi:type='zip:UnZipFile']", namespaces=nsmap) logging.debug(f"unzip_nodes {unzip_nodes}") diff --git a/qc_otx/checks/zip_file_checker/type_safe_zip_file.py b/qc_otx/checks/zip_file_checker/type_safe_zip_file.py index 7c4f985..9a12e9d 100644 --- a/qc_otx/checks/zip_file_checker/type_safe_zip_file.py +++ b/qc_otx/checks/zip_file_checker/type_safe_zip_file.py @@ -39,6 +39,12 @@ def check_rule(checker_data: models.CheckerData) -> None: status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + CHECKER_ID, + f"xsi is not in nsmap or zip is not in nsmap. Skip the check.", + ) + return zip_nodes = tree.xpath("//*[@xsi:type='zip:ZipFile']", namespaces=nsmap) diff --git a/qc_otx/main.py b/qc_otx/main.py index a8a8aab..7c15b84 100644 --- a/qc_otx/main.py +++ b/qc_otx/main.py @@ -66,6 +66,12 @@ def execute_checker( status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + checker.CHECKER_ID, + "Preconditions are not satisfied. Skip the check.", + ) + return # Checker definition setting. If not satisfied then set status as SKIPPED and return @@ -82,6 +88,12 @@ def execute_checker( status=StatusType.SKIPPED, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, + checker.CHECKER_ID, + f"Version {schema_version} is lower than definition setting {definition_setting}. Skip the check.", + ) + return # Execute checker @@ -98,7 +110,7 @@ def execute_checker( checker_id=checker.CHECKER_ID, status=StatusType.COMPLETED, ) - except Exception: + except Exception as e: # If any exception occurs during the check, set the status as ERROR checker_data.result.set_checker_status( checker_bundle_name=constants.BUNDLE_NAME, @@ -106,6 +118,10 @@ def execute_checker( status=StatusType.ERROR, ) + checker_data.result.add_checker_summary( + constants.BUNDLE_NAME, checker.CHECKER_ID, f"Error: {str(e)}." + ) + def run_checks(config: Configuration, result: Result) -> None: root = etree.parse(config.get_config_param("InputFile")) @@ -204,7 +220,8 @@ def main(): result.write_to_file( config.get_checker_bundle_param( checker_bundle_name=constants.BUNDLE_NAME, param_name="resultFile" - ) + ), + generate_summary=True, ) if args.generate_markdown: From 98def9dab85bd66185f8bd0583222a510e6ddb06 Mon Sep 17 00:00:00 2001 From: Hoang Tung Dinh Date: Tue, 17 Sep 2024 16:34:52 +0200 Subject: [PATCH 4/5] Add exception to logging (#33) Signed-off-by: hoangtungdinh <11166240+hoangtungdinh@users.noreply.github.com> --- qc_otx/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qc_otx/main.py b/qc_otx/main.py index 7c15b84..767badc 100644 --- a/qc_otx/main.py +++ b/qc_otx/main.py @@ -122,6 +122,8 @@ def execute_checker( constants.BUNDLE_NAME, checker.CHECKER_ID, f"Error: {str(e)}." ) + logging.exception(f"An error occurred in {checker.CHECKER_ID}.") + def run_checks(config: Configuration, result: Result) -> None: root = etree.parse(config.get_config_param("InputFile")) From 3b04ac25f4ce8b2213b40421f3f7e14cfdbf7b74 Mon Sep 17 00:00:00 2001 From: Hoang Tung Dinh Date: Mon, 23 Sep 2024 12:12:29 +0200 Subject: [PATCH 5/5] Use the two new functions supported in baselib (#34) Signed-off-by: hoangtungdinh <11166240+hoangtungdinh@users.noreply.github.com> Co-authored-by: hoangtungdinh <11166240+hoangtungdinh@users.noreply.github.com> --- poetry.lock | 196 ++++++++++++++++++++++++------------------------- qc_otx/main.py | 21 ++---- 2 files changed, 106 insertions(+), 111 deletions(-) diff --git a/poetry.lock b/poetry.lock index 54a71a0..3aab2d9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -29,7 +29,7 @@ pydantic-xml = "^2.11.0" type = "git" url = "https://github.com/asam-ev/qc-baselib-py.git" reference = "develop" -resolved_reference = "8ed36cb58c8994b9674f7c6ea74992dacb65bdaf" +resolved_reference = "bfed12fc6f1bbd2cab97f74a6c9aa0e0faaef7b3" [[package]] name = "black" @@ -316,13 +316,13 @@ files = [ [[package]] name = "platformdirs" -version = "4.3.3" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.3.3-py3-none-any.whl", hash = "sha256:50a5450e2e84f44539718293cbb1da0a0885c9d14adf21b77bae4e66fc99d9b5"}, - {file = "platformdirs-4.3.3.tar.gz", hash = "sha256:d4e0b7d8ec176b341fb03cb11ca12d0276faa8c485f9cd218f613840463fc2c0"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] @@ -347,18 +347,18 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.9.1" +version = "2.9.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.9.1-py3-none-any.whl", hash = "sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612"}, - {file = "pydantic-2.9.1.tar.gz", hash = "sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2"}, + {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, + {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.23.3" +pydantic-core = "2.23.4" typing-extensions = [ {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, {version = ">=4.6.1", markers = "python_version < \"3.13\""}, @@ -370,100 +370,100 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.23.3" +version = "2.23.4" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.23.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6"}, - {file = "pydantic_core-2.23.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba"}, - {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee"}, - {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe"}, - {file = "pydantic_core-2.23.3-cp310-none-win32.whl", hash = "sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b"}, - {file = "pydantic_core-2.23.3-cp310-none-win_amd64.whl", hash = "sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83"}, - {file = "pydantic_core-2.23.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27"}, - {file = "pydantic_core-2.23.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8"}, - {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48"}, - {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5"}, - {file = "pydantic_core-2.23.3-cp311-none-win32.whl", hash = "sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1"}, - {file = "pydantic_core-2.23.3-cp311-none-win_amd64.whl", hash = "sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa"}, - {file = "pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305"}, - {file = "pydantic_core-2.23.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c"}, - {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c"}, - {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab"}, - {file = "pydantic_core-2.23.3-cp312-none-win32.whl", hash = "sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c"}, - {file = "pydantic_core-2.23.3-cp312-none-win_amd64.whl", hash = "sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b"}, - {file = "pydantic_core-2.23.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f"}, - {file = "pydantic_core-2.23.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855"}, - {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4"}, - {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d"}, - {file = "pydantic_core-2.23.3-cp313-none-win32.whl", hash = "sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8"}, - {file = "pydantic_core-2.23.3-cp313-none-win_amd64.whl", hash = "sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1"}, - {file = "pydantic_core-2.23.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d063c6b9fed7d992bcbebfc9133f4c24b7a7f215d6b102f3e082b1117cddb72c"}, - {file = "pydantic_core-2.23.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6cb968da9a0746a0cf521b2b5ef25fc5a0bee9b9a1a8214e0a1cfaea5be7e8a4"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbefe079a520c5984e30e1f1f29325054b59534729c25b874a16a5048028d16"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbaaf2ef20d282659093913da9d402108203f7cb5955020bd8d1ae5a2325d1c4"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb539d7e5dc4aac345846f290cf504d2fd3c1be26ac4e8b5e4c2b688069ff4cf"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e6f33503c5495059148cc486867e1d24ca35df5fc064686e631e314d959ad5b"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b07490bc2f6f2717b10c3969e1b830f5720b632f8ae2f3b8b1542394c47a8e"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03795b9e8a5d7fda05f3873efc3f59105e2dcff14231680296b87b80bb327295"}, - {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c483dab0f14b8d3f0df0c6c18d70b21b086f74c87ab03c59250dbf6d3c89baba"}, - {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b2682038e255e94baf2c473dca914a7460069171ff5cdd4080be18ab8a7fd6e"}, - {file = "pydantic_core-2.23.3-cp38-none-win32.whl", hash = "sha256:f4a57db8966b3a1d1a350012839c6a0099f0898c56512dfade8a1fe5fb278710"}, - {file = "pydantic_core-2.23.3-cp38-none-win_amd64.whl", hash = "sha256:13dd45ba2561603681a2676ca56006d6dee94493f03d5cadc055d2055615c3ea"}, - {file = "pydantic_core-2.23.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82da2f4703894134a9f000e24965df73cc103e31e8c31906cc1ee89fde72cbd8"}, - {file = "pydantic_core-2.23.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dd9be0a42de08f4b58a3cc73a123f124f65c24698b95a54c1543065baca8cf0e"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89b731f25c80830c76fdb13705c68fef6a2b6dc494402987c7ea9584fe189f5d"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6de1ec30c4bb94f3a69c9f5f2182baeda5b809f806676675e9ef6b8dc936f28"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb68b41c3fa64587412b104294b9cbb027509dc2f6958446c502638d481525ef"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c3980f2843de5184656aab58698011b42763ccba11c4a8c35936c8dd6c7068c"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94f85614f2cba13f62c3c6481716e4adeae48e1eaa7e8bac379b9d177d93947a"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:510b7fb0a86dc8f10a8bb43bd2f97beb63cffad1203071dc434dac26453955cd"}, - {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1eba2f7ce3e30ee2170410e2171867ea73dbd692433b81a93758ab2de6c64835"}, - {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b259fd8409ab84b4041b7b3f24dcc41e4696f180b775961ca8142b5b21d0e70"}, - {file = "pydantic_core-2.23.3-cp39-none-win32.whl", hash = "sha256:40d9bd259538dba2f40963286009bf7caf18b5112b19d2b55b09c14dde6db6a7"}, - {file = "pydantic_core-2.23.3-cp39-none-win_amd64.whl", hash = "sha256:5a8cd3074a98ee70173a8633ad3c10e00dcb991ecec57263aacb4095c5efb958"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e89513f014c6be0d17b00a9a7c81b1c426f4eb9224b15433f3d98c1a071f8433"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4f62c1c953d7ee375df5eb2e44ad50ce2f5aff931723b398b8bc6f0ac159791a"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2718443bc671c7ac331de4eef9b673063b10af32a0bb385019ad61dcf2cc8f6c"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d90e08b2727c5d01af1b5ef4121d2f0c99fbee692c762f4d9d0409c9da6541"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b676583fc459c64146debea14ba3af54e540b61762dfc0613dc4e98c3f66eeb"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:50e4661f3337977740fdbfbae084ae5693e505ca2b3130a6d4eb0f2281dc43b8"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:68f4cf373f0de6abfe599a38307f4417c1c867ca381c03df27c873a9069cda25"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:59d52cf01854cb26c46958552a21acb10dd78a52aa34c86f284e66b209db8cab"}, - {file = "pydantic_core-2.23.3.tar.gz", hash = "sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, + {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, + {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, + {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, + {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, + {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, + {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, + {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, + {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, + {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, + {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, + {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, + {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, + {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, ] [package.dependencies] diff --git a/qc_otx/main.py b/qc_otx/main.py index 767badc..5203ecf 100644 --- a/qc_otx/main.py +++ b/qc_otx/main.py @@ -43,17 +43,10 @@ def execute_checker( ) # Register rule uid - splitted_rule_uid = checker.RULE_UID.split(":") - if len(splitted_rule_uid) != 4: - raise RuntimeError(f"Invalid rule uid: {checker.RULE_UID}") - - checker_data.result.register_rule( + checker_data.result.register_rule_by_uid( checker_bundle_name=constants.BUNDLE_NAME, checker_id=checker.CHECKER_ID, - emanating_entity=splitted_rule_uid[0], - standard=splitted_rule_uid[1], - definition_setting=splitted_rule_uid[2], - rule_full_name=splitted_rule_uid[3], + rule_uid=checker.RULE_UID, ) # Check preconditions. If not satisfied then set status as SKIPPED and return @@ -77,6 +70,10 @@ def execute_checker( # Checker definition setting. If not satisfied then set status as SKIPPED and return if required_definition_setting: schema_version = checker_data.schema_version + splitted_rule_uid = checker.RULE_UID.split(":") + if len(splitted_rule_uid) != 4: + raise RuntimeError(f"Invalid rule uid: {checker.RULE_UID}") + definition_setting = splitted_rule_uid[2] if ( schema_version is None @@ -213,12 +210,10 @@ def main(): ) result.set_result_version(version=constants.BUNDLE_VERSION) - input_file_path = config.get_config_param("InputFile") - input_param = ParamType(name="InputFile", value=input_file_path) - result.get_checker_bundle_result(constants.BUNDLE_NAME).params.append(input_param) - run_checks(config, result) + result.copy_param_from_config(config) + result.write_to_file( config.get_checker_bundle_param( checker_bundle_name=constants.BUNDLE_NAME, param_name="resultFile"