Skip to content

Commit

Permalink
release: 🔖 version 0.4.1
Browse files Browse the repository at this point in the history
  • Loading branch information
kikkomep committed Oct 30, 2024
2 parents 8d1809a + e6f2a69 commit 34a93de
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 32 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "roc-validator"
version = "0.4.0"
version = "0.4.1"
description = "A Python package to validate RO-Crates"
authors = [
"Marco Enrico Piras <[email protected]>",
Expand Down
88 changes: 62 additions & 26 deletions rocrate_validator/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from rdflib import RDF, RDFS, Graph, Namespace, URIRef

import rocrate_validator.log as logging
from rocrate_validator import __version__
from rocrate_validator.constants import (DEFAULT_ONTOLOGY_FILE,
DEFAULT_PROFILE_IDENTIFIER,
DEFAULT_PROFILE_README_FILE,
Expand Down Expand Up @@ -388,6 +389,14 @@ def __repr__(self) -> str:
def __str__(self) -> str:
return f"{self.name} ({self.identifier})"

def to_dict(self) -> dict:
return {
"identifier": self.identifier,
"uri": self.uri,
"name": self.name,
"description": self.description
}

@staticmethod
def __extract_version_from_token__(token: str) -> Optional[str]:
if not token:
Expand Down Expand Up @@ -728,6 +737,19 @@ def __repr__(self):
def __str__(self) -> str:
return self.name

def to_dict(self, with_profile: bool = True, with_checks: bool = True) -> dict:
result = {
"identifier": self.identifier,
"name": self.name,
"description": self.description,
"order": self.order_number
}
if with_profile:
result["profile"] = self.profile.to_dict()
if with_checks:
result["checks"] = [_.to_dict(with_requirement=False, with_profile=False) for _ in self._checks]
return result


class RequirementLoader:

Expand Down Expand Up @@ -893,6 +915,19 @@ def overridden(self) -> bool:
def execute_check(self, context: ValidationContext) -> bool:
raise NotImplementedError()

def to_dict(self, with_requirement: bool = True, with_profile: bool = True) -> dict:
result = {
"identifier": self.identifier,
"label": self.relative_identifier,
"order": self.order_number,
"name": self.name,
"description": self.description,
"severity": self.severity.name
}
if with_requirement:
result["requirement"] = self.requirement.to_dict(with_profile=with_profile, with_checks=False)
return result

def __eq__(self, other: object) -> bool:
if not isinstance(other, RequirementCheck):
raise ValueError(f"Cannot compare RequirementCheck with {type(other)}")
Expand Down Expand Up @@ -942,18 +977,12 @@ class CheckIssue:
check (RequirementCheck): The check that generated the issue
"""

# TODO:
# 2. CheckIssue has the check, so it is able to determine the level and the Severity
# without having it provided through an additional argument.
def __init__(self, severity: Severity,
def __init__(self,
check: RequirementCheck,
message: Optional[str] = None,
resultPath: Optional[str] = None,
focusNode: Optional[str] = None,
value: Optional[str] = None):
if not isinstance(severity, Severity):
raise TypeError(f"CheckIssue constructed with a severity '{severity}' of type {type(severity)}")
self._severity = severity
self._message = message
self._check: RequirementCheck = check
self._resultPath = resultPath
Expand All @@ -973,7 +1002,7 @@ def level(self) -> RequirementLevel:
@property
def severity(self) -> Severity:
"""Severity of the RequirementLevel associated with this check."""
return self._severity
return self._check.severity

@property
def level_name(self) -> str:
Expand All @@ -999,35 +1028,44 @@ def value(self) -> Optional[str]:
def __eq__(self, other: object) -> bool:
return isinstance(other, CheckIssue) and \
self._check == other._check and \
self._severity == other._severity and \
self._message == other._message

def __lt__(self, other: object) -> bool:
if not isinstance(other, CheckIssue):
raise TypeError(f"Cannot compare {type(self)} with {type(other)}")
return (self._check, self._severity, self._message) < (other._check, other._severity, other._message)
return (self._check, self._message) < (other._check, other._message)

def __hash__(self) -> int:
return hash((self._check, self._severity, self._message))
return hash((self._check, self._message))

def __repr__(self) -> str:
return f'CheckIssue(severity={self.severity}, check={self.check}, message={self.message})'

def __str__(self) -> str:
return f"{self.severity}: {self.message} ({self.check})"

def to_dict(self) -> dict:
return {
def to_dict(self, with_check: bool = True,
with_requirement: bool = True, with_profile: bool = True) -> dict:
result = {
"severity": self.severity.name,
"message": self.message,
"check": self.check.name,
"resultPath": self.resultPath,
"focusNode": self.focusNode,
"value": self.value
}
if with_check:
result["check"] = self.check.to_dict(with_requirement=with_requirement, with_profile=with_profile)
return result

def to_json(self) -> str:
return json.dumps(self.to_dict(), indent=4, cls=CustomEncoder)
def to_json(self,
with_checks: bool = True,
with_requirements: bool = True,
with_profile: bool = True) -> str:
return json.dumps(
self.to_dict(
with_check=with_checks,
with_requirement=with_requirements,
with_profile=with_profile
), indent=4, cls=CustomEncoder)

# @property
# def code(self) -> int:
Expand Down Expand Up @@ -1139,18 +1177,15 @@ def add_issue(self, issue: CheckIssue):
def add_check_issue(self,
message: str,
check: RequirementCheck,
severity: Optional[Severity] = None,
resultPath: Optional[str] = None,
focusNode: Optional[str] = None,
value: Optional[str] = None) -> CheckIssue:
sev_value = severity if severity is not None else check.severity
c = CheckIssue(sev_value, check, message, resultPath=resultPath, focusNode=focusNode, value=value)
# self._issues.append(c)
c = CheckIssue(check, message, resultPath=resultPath, focusNode=focusNode, value=value)
bisect.insort(self._issues, c)
return c

def add_error(self, message: str, check: RequirementCheck) -> CheckIssue:
return self.add_check_issue(message, check, Severity.REQUIRED)
return self.add_check_issue(message, check)

# --- Requirements ---
@property
Expand Down Expand Up @@ -1183,15 +1218,16 @@ def __eq__(self, other: object) -> bool:
return self._issues == other._issues

def to_dict(self) -> dict:
allowed_properties = ["data_path", "profiles_path",
"profile_identifier", "inherit_profiles", "requirement_severity", "abort_on_first"]
return {
"rocrate": str(self.rocrate_path),
allowed_properties = ["profile_identifier", "inherit_profiles", "requirement_severity", "abort_on_first"]
result = {
"validation_settings": {key: self.validation_settings[key]
for key in allowed_properties if key in self.validation_settings},
"passed": self.passed(self.context.settings["requirement_severity"]),
"issues": [issue.to_dict() for issue in self.issues]
}
# add validator version to the settings
result["validation_settings"]["rocrate-validator-version"] = __version__
return result

def to_json(self, path: Optional[Path] = None) -> str:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def check_workflow(self, context: ValidationContext) -> bool:
context.result.add_check_issue("main workflow does not exist in metadata file", self)
return False
if not main_workflow.is_available():
context.result.add_check_issue("Main Workflow {main_workflow.id} not found in crate", self)
context.result.add_check_issue(f"Main Workflow {main_workflow.id} not found in crate", self)
return False
return True
except ValueError as e:
Expand Down
6 changes: 6 additions & 0 deletions rocrate_validator/requirements/python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,14 @@ def __init_checks__(self):
severity = None
try:
severity = member.severity
logger.debug("Severity set for check '%r' from decorator: %r", check_name, severity)
except Exception:
pass
if not severity:
logger.debug(f"No explicit severity set for check '{check_name}' from decorator."
f"Getting severity from path: {self.severity_from_path}")
severity = self.severity_from_path or Severity.REQUIRED
logger.debug("Severity log: %r", severity)
check = self.requirement_check_class(self,
check_name,
member,
Expand Down
1 change: 0 additions & 1 deletion rocrate_validator/requirements/shacl/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
c = shacl_context.result.add_check_issue(
message=violation.get_result_message(shacl_context.rocrate_path),
check=requirementCheck,
severity=violation.get_result_severity(),
resultPath=violation.resultPath.toPython() if violation.resultPath else None,
focusNode=make_uris_relative(
violation.focusNode.toPython(), shacl_context.publicID),
Expand Down
7 changes: 6 additions & 1 deletion rocrate_validator/requirements/shacl/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __init__(self, node: Node, graph: Graph, parent: Optional[SHACLNode] = None)
def name(self) -> str:
"""Return the name of the shape"""
if not self._name:
self._name = self._node.split("#")[-1] if "#" in self.node else self._node.split("/")[-1]
self._name = self.node_name
return self._name or self._node.split("/")[-1]

@name.setter
Expand Down Expand Up @@ -86,6 +86,11 @@ def node(self):
"""Return the node of the shape"""
return self._node

@property
def node_name(self):
"""Return the name of the node"""
return self._node.split("#")[-1] if "#" in self.node else self._node.split("/")[-1]

@property
def graph(self):
"""Return the subgraph of the shape"""
Expand Down
2 changes: 1 addition & 1 deletion tests/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def do_entity_test(
f"\"{expected_triggered_requirement}\" was not found in the failed requirements"

# check requirement issues
detected_issues = [issue.message for issue in result.get_issues(models.Severity.RECOMMENDED)
detected_issues = [issue.message for issue in result.get_issues(requirement_severity)
if issue.message is not None]
logger.debug("Detected issues: %s", detected_issues)
logger.debug("Expected issues: %s", expected_triggered_issues)
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/requirements/test_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ def check_profile(profile, check, inherited_profiles, overridden_by, override):

# Get the check
check = requirement.get_checks()[0]
logger.debug("The check: %r of requirement %r of the profiles %f", check, requirement, profile.token)
logger.debug("The check: %r of requirement %r of the profiles %s", check, requirement, profile.token)

# Check the profile 'a'
if profile.token == "a":
Expand Down

0 comments on commit 34a93de

Please sign in to comment.