From 7a15d37cb370257b940ccc1cb45f140235b11aa4 Mon Sep 17 00:00:00 2001 From: patrickpa Date: Tue, 11 Jun 2024 11:49:38 +0200 Subject: [PATCH] Improve code readability and documentation Signed-off-by: patrickpa --- README.md | 2 ++ qc_baselib/models/result.py | 46 +++++++++++++++++++++++++++++++------ qc_baselib/result.py | 1 + tests/test_result.py | 46 +++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b5232b4..ece4f04 100644 --- a/README.md +++ b/README.md @@ -290,6 +290,8 @@ Issue id: 0 Issue level: 3 ``` +For more use case examples refer to the library [tests](tests/). + ## Tests - Install module on development mode diff --git a/qc_baselib/models/result.py b/qc_baselib/models/result.py index 288d42a..70afcd7 100644 --- a/qc_baselib/models/result.py +++ b/qc_baselib/models/result.py @@ -55,7 +55,7 @@ class RuleType(BaseXmlModel, tag="AddressedRule"): Type containing the Rule Schema rules and its required checks More information at: - https://github.com/asam-ev/qc-framework/blob/develop/doc/manual/rule_uid_schema.md + https://github.com/asam-ev/qc-framework/blob/main/doc/manual/rule_uid_schema.md """ # The current implementation makes Rule members required, so no element can @@ -83,11 +83,15 @@ class RuleType(BaseXmlModel, tag="AddressedRule"): rule_uid: str = attr( name="ruleUID", default="", - pattern=r"^((\w+(\.\w+)+)):(([a-z]+))?:(([0-9]+(\.[0-9]+)+))?:((([a-z][\w_]*)\.)*)([a-z][\w_]*)$", + pattern=r"^((\w+(\.\w+)+)):(([a-z]+)):(([0-9]+(\.[0-9]+)+)):((([a-z][\w_]*)\.)*)([a-z][\w_]*)$", ) @model_validator(mode="after") def load_fields_into_uid(self) -> Any: + """ + Loads fields into rule uid if all required fields are present. + Otherwise it skips initialization. + """ if ( self.emanating_entity != "" and self.standard != "" @@ -100,9 +104,10 @@ def load_fields_into_uid(self) -> Any: @model_validator(mode="after") def load_uid_into_fields(self) -> Any: - if self.rule_uid == "": - raise ValueError("Empty initialization of AddressedRule with no rule uid") - + """ + Loads fields from rule uid if no field is present in the model. + Otherwise it skips initialization. + """ if ( self.emanating_entity == "" and self.standard == "" @@ -113,7 +118,7 @@ def load_uid_into_fields(self) -> Any: if len(elements) < 4: raise ValueError( - "Not enough elements to parse Rule UID. This should follow pattern described at https://github.com/asam-ev/qc-framework/blob/develop/doc/manual/rule_uid_schema.md" + "Not enough elements to parse Rule UID. This should follow pattern described at https://github.com/asam-ev/qc-framework/blob/main/doc/manual/rule_uid_schema.md" ) self.emanating_entity = elements[0] @@ -123,6 +128,25 @@ def load_uid_into_fields(self) -> Any: return self + @model_validator(mode="after") + def check_any_empty(self) -> Any: + """ + Validates if any field is empty after initialization. No field should + be leave empty after a successful initialization happens. + """ + if self.rule_uid == "": + raise ValueError("Empty initialization of rule_uid") + if self.emanating_entity == "": + raise ValueError("Empty initialization of emanating_entity") + if self.standard == "": + raise ValueError("Empty initialization of standard") + if self.definition_setting == "": + raise ValueError("Empty initialization of definition_setting") + if self.rule_full_name == "": + raise ValueError("Empty initialization of rule_full_name") + + return self + class IssueType(BaseXmlModel, tag="Issue"): locations: List[LocationType] = [] @@ -132,7 +156,7 @@ class IssueType(BaseXmlModel, tag="Issue"): rule_uid: str = attr( name="ruleUID", default="", - pattern=r"^((\w+(\.\w+)+)):(([a-z]+))?:(([0-9]+(\.[0-9]+)+))?:((([a-z][\w_]*)\.)*)([a-z][\w_]*)$", + pattern=r"^((\w+(\.\w+)+)):(([a-z]+)):(([0-9]+(\.[0-9]+)+)):((([a-z][\w_]*)\.)*)([a-z][\w_]*)$", ) @@ -172,6 +196,14 @@ def check_issue_ruleUID_matches_addressed_rules(self) -> Any: ) return self + @model_validator(mode="after") + def check_skipped_status_containing_issues(self) -> Any: + if self.status == StatusType.SKIPPED and len(self.issues) > 0: + raise ValueError( + f"{self.checker_id}\nCheckers with skipped status cannot contain issues. Issues found: {len(self.issues)}" + ) + return self + class CheckerBundleType(BaseXmlModel, tag="CheckerBundle"): params: List[ParamType] = [] diff --git a/qc_baselib/result.py b/qc_baselib/result.py index f0f0c4e..e08bf47 100644 --- a/qc_baselib/result.py +++ b/qc_baselib/result.py @@ -292,6 +292,7 @@ def set_checker_status( bundle = self._get_checker_bundle(checker_bundle_name=checker_bundle_name) checker = self._get_checker(bundle=bundle, checker_id=checker_id) checker.status = status + result.CheckerType.model_validate(checker) def get_result_version(self) -> str: return self._report_results.version diff --git a/tests/test_result.py b/tests/test_result.py index 334e666..ca382ef 100644 --- a/tests/test_result.py +++ b/tests/test_result.py @@ -301,3 +301,49 @@ def test_create_rule_id_validation() -> None: definition_setting="1.0.0", rule_full_name="", ) + + +def test_set_checker_status_skipped_with_issues() -> None: + result = Result() + + result.register_checker_bundle( + name="TestBundle", + build_date="2024-05-31", + description="Example checker bundle", + version="0.0.1", + summary="Tested example checkers", + ) + + result.register_checker( + checker_bundle_name="TestBundle", + checker_id="TestChecker", + description="Test checker", + summary="Executed evaluation", + ) + + rule_uid = result.register_rule( + checker_bundle_name="TestBundle", + checker_id="TestChecker", + emanating_entity="test.com", + standard="qc", + definition_setting="1.0.0", + rule_full_name="qwerty.qwerty", + ) + + issue_id_0 = result.register_issue( + checker_bundle_name="TestBundle", + checker_id="TestChecker", + description="Issue found at odr", + level=IssueSeverity.INFORMATION, + rule_uid=rule_uid, + ) + + with pytest.raises( + ValidationError, + match=r".*\nCheckers with skipped status cannot contain issues\. .*", + ) as exc_info: + result.set_checker_status( + checker_bundle_name="TestBundle", + checker_id="TestChecker", + status=StatusType.SKIPPED, + )