1616from timeit import default_timer as timer
1717from typing import Optional
1818
19- from rocrate_validator .utils import log as logging
2019from rocrate_validator .errors import ROCrateMetadataNotFoundError
2120from rocrate_validator .events import EventType
22- from rocrate_validator .models import (LevelCollection , Requirement ,
23- RequirementCheck ,
24- RequirementCheckValidationEvent ,
25- SkipRequirementCheck , ValidationContext )
21+ from rocrate_validator .models import (
22+ LevelCollection ,
23+ Requirement ,
24+ RequirementCheck ,
25+ RequirementCheckValidationEvent ,
26+ SkipRequirementCheck ,
27+ ValidationContext ,
28+ )
2629from rocrate_validator .requirements .shacl .models import Shape
27- from rocrate_validator .requirements .shacl .utils import make_uris_relative
30+ from rocrate_validator .requirements .shacl .utils import make_uris_relative , resolve_parent_shape
2831from rocrate_validator .requirements .shacl .validator import (
29- SHACLValidationAlreadyProcessed , SHACLValidationContext ,
30- SHACLValidationContextManager , SHACLValidationSkip , SHACLValidator ,
31- SHACLViolation )
32+ SHACLValidationAlreadyProcessed ,
33+ SHACLValidationContext ,
34+ SHACLValidationContextManager ,
35+ SHACLValidationSkip ,
36+ SHACLValidator ,
37+ SHACLViolation ,
38+ )
39+ from rocrate_validator .utils import log as logging
3240
3341logger = logging .getLogger (__name__ )
3442
@@ -41,25 +49,27 @@ class SHACLCheck(RequirementCheck):
4149 # Map shape to requirement check instances
4250 __instances__ = {}
4351
44- def __init__ (self ,
45- requirement : Requirement ,
46- shape : Shape ,
47- name : Optional [str ] = None ,
48- root : bool = False ,
49- hidden : Optional [bool ] = None ,
50- level : Optional [bool ] = None ) -> None :
52+ def __init__ (
53+ self ,
54+ requirement : Requirement ,
55+ shape : Shape ,
56+ name : Optional [str ] = None ,
57+ root : bool = False ,
58+ hidden : Optional [bool ] = None ,
59+ level : Optional [bool ] = None ,
60+ ) -> None :
5161 self ._shape = shape
5262 self ._root = root
5363 # init the check
54- super ().__init__ (requirement ,
55- name or shape . name if shape and shape . name
56- else shape .parent .name if shape .parent
57- else None ,
58- description = shape .description if shape and shape . description
59- else shape . parent . description if shape . parent
60- else None ,
61- level = level ,
62- hidden = hidden )
64+ super ().__init__ (
65+ requirement ,
66+ ( name or shape . name if shape and shape . name else shape .parent .name if shape .parent else None ),
67+ description = (
68+ shape . description if shape and shape . description else shape .parent . description if shape . parent else None
69+ ),
70+ level = level ,
71+ hidden = hidden ,
72+ )
6373 # store the instance
6474 SHACLCheck .__add_instance__ (shape , self )
6575
@@ -69,10 +79,14 @@ def __init__(self,
6979 declared_level = shape .get_declared_level ()
7080 if declared_level :
7181 if shape .level .severity != requirement_level_from_path .severity :
72- logger .warning ("Mismatch in requirement level for check \" %s\" : "
73- "shape level %s does not match the level from the containing folder %s. "
74- "Consider moving the shape property or removing the severity property." ,
75- self .name , shape .level , requirement_level_from_path )
82+ logger .warning (
83+ 'Mismatch in requirement level for check "%s": '
84+ "shape level %s does not match the level from the containing folder %s. "
85+ "Consider moving the shape property or removing the severity property." ,
86+ self .name ,
87+ shape .level ,
88+ requirement_level_from_path ,
89+ )
7690 self ._level = level
7791
7892 @property
@@ -85,7 +99,11 @@ def root(self) -> bool:
8599
86100 @property
87101 def description (self ) -> str :
88- return self ._shape .description
102+ if self ._shape .description :
103+ return self ._shape .description
104+ if self ._shape .parent and self ._shape .parent .description :
105+ return self ._shape .parent .description
106+ return f"Check for { self ._shape .name } " if self ._shape .name else "SHACL validation check"
89107
90108 def __compute_requirement_level__ (self ) -> LevelCollection :
91109 if self ._shape and self ._shape .get_declared_level ():
@@ -107,31 +125,50 @@ def severity(self) -> str:
107125 def execute_check (self , context : ValidationContext ):
108126 logger .debug ("Starting check %s" , self )
109127 try :
110- logger .debug ("SHACL Validation of profile %s requirement %s started" ,
111- self .requirement .profile .identifier , self .identifier )
128+ logger .debug (
129+ "SHACL Validation of profile %s requirement %s started" ,
130+ self .requirement .profile .identifier ,
131+ self .identifier ,
132+ )
112133 with SHACLValidationContextManager (self , context ) as ctx :
113134 # The check is executed only if the profile is the most specific one
114- logger .debug ("SHACL Validation of requirement check %s (profile: %s) started" ,
115- self .requirement .profile .identifier , self .identifier )
135+ logger .debug (
136+ "SHACL Validation of requirement check %s (profile: %s) started" ,
137+ self .requirement .profile .identifier ,
138+ self .identifier ,
139+ )
116140 result = self .__do_execute_check__ (ctx )
117141 ctx .current_validation_result = self .identifier not in result
118- logger .debug ("SHACL Validation of requirement check %s (profile: %s) finished with result %s" ,
119- self .requirement .profile .identifier , self .identifier , ctx .current_validation_result )
142+ logger .debug (
143+ "SHACL Validation of requirement check %s (profile: %s) finished with result %s" ,
144+ self .requirement .profile .identifier ,
145+ self .identifier ,
146+ ctx .current_validation_result ,
147+ )
120148 return ctx .current_validation_result
121149 except SHACLValidationAlreadyProcessed :
122- logger .debug ("SHACL Validation of requirement check %s (profile: %s) already processed" ,
123- self .requirement .identifier , self .requirement .profile .identifier )
150+ logger .debug (
151+ "SHACL Validation of requirement check %s (profile: %s) already processed" ,
152+ self .requirement .identifier ,
153+ self .requirement .profile .identifier ,
154+ )
124155 # The check belongs to a profile which has already been processed
125156 # so we can skip the validation and return the specific result for the check
126157 return self .identifier not in [i .check .identifier for i in context .result .get_issues ()]
127158 except SHACLValidationSkip as e :
128- logger .debug ("SHACL Validation of profile %s requirement %s skipped" ,
129- self .requirement .profile .identifier , self .identifier )
159+ logger .debug (
160+ "SHACL Validation of profile %s requirement %s skipped" ,
161+ self .requirement .profile .identifier ,
162+ self .identifier ,
163+ )
130164 # The validation is postponed to the more specific profiles
131165 # so the check is not considered as failed.
132166 raise SkipRequirementCheck (self , str (e ))
133167 except ROCrateMetadataNotFoundError as e :
134- logger .debug ("Unable to perform metadata validation due to missing metadata file: %s" , e )
168+ logger .debug (
169+ "Unable to perform metadata validation due to missing metadata file: %s" ,
170+ e ,
171+ )
135172 return False
136173
137174 def __do_execute_check__ (self , shacl_context : SHACLValidationContext ):
@@ -151,12 +188,17 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
151188 end_time = timer ()
152189 logger .debug (f"Execution time for getting data graph: { end_time - start_time } seconds" )
153190 except json .decoder .JSONDecodeError as e :
154- logger .debug ("Unable to perform metadata validation "
155- "due to one or more errors in the JSON-LD data file: %s" , e )
191+ logger .debug (
192+ "Unable to perform metadata validation " "due to one or more errors in the JSON-LD data file: %s" ,
193+ e ,
194+ )
156195 shacl_context .result .add_issue (
157- "Unable to perform metadata validation due to one or more errors in the JSON-LD data file" , self )
196+ "Unable to perform metadata validation due to one or more errors in the JSON-LD data file" ,
197+ self ,
198+ )
158199 raise ROCrateMetadataNotFoundError (
159- "Unable to perform metadata validation due to one or more errors in the JSON-LD data file" )
200+ "Unable to perform metadata validation due to one or more errors in the JSON-LD data file"
201+ )
160202
161203 # Begin the timer
162204 start_time = timer ()
@@ -177,7 +219,10 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
177219 start_time = timer ()
178220 shacl_validator = SHACLValidator (shapes_graph = shapes_graph , ont_graph = ontology_graph )
179221 shacl_result = shacl_validator .validate (
180- data_graph = data_graph , ontology_graph = ontology_graph , ** shacl_context .settings .to_dict ())
222+ data_graph = data_graph ,
223+ ontology_graph = ontology_graph ,
224+ ** shacl_context .settings .to_dict (),
225+ )
181226 # shacl_result.results_graph.serialize("logs/validation_results.ttl", format="turtle")
182227 # parse the validation result
183228 end_time = timer ()
@@ -190,8 +235,10 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
190235 # if the validation fails, process the failed checks
191236 failed_requirements_checks = set ()
192237 failed_requirements_checks_violations : dict [str , SHACLViolation ] = {}
193- failed_requirement_checks_notified = [_ .check .identifier for _ in shacl_context .result .get_issues (
194- min_severity = shacl_context .settings .requirement_severity )]
238+ failed_requirement_checks_notified = [
239+ _ .check .identifier
240+ for _ in shacl_context .result .get_issues (min_severity = shacl_context .settings .requirement_severity )
241+ ]
195242
196243 logger .debug ("Parsing Validation with result: %s" , shacl_result )
197244 # process the failed checks to extract the requirement checks involved
@@ -234,8 +281,10 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
234281 for requirementCheck in sorted (failed_requirements_checks , key = lambda x : (x .identifier , x .severity )):
235282 # if the check is not in the current profile
236283 # and the disable_inherited_profiles_reporting is enabled, skip it
237- if requirementCheck .requirement .profile != shacl_context .current_validation_profile and \
238- shacl_context .settings .disable_inherited_profiles_issue_reporting :
284+ if (
285+ requirementCheck .requirement .profile != shacl_context .current_validation_profile
286+ and shacl_context .settings .disable_inherited_profiles_issue_reporting
287+ ):
239288 continue
240289 for violation in failed_requirements_checks_violations [requirementCheck .identifier ]:
241290 violating_entity = make_uris_relative (violation .focusNode .toPython (), shacl_context .publicID )
@@ -246,13 +295,18 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
246295 # check if the violation is already registered
247296 # and skip the requirement check if it is
248297 for check_issue in registered_check_issues :
249- if check_issue .message == violation_message and \
250- check_issue .violatingProperty == violating_property and \
251- check_issue .violatingEntity == violating_entity and \
252- check_issue .violatingPropertyValue == violation .value :
298+ if (
299+ check_issue .message == violation_message
300+ and check_issue .violatingProperty == violating_property
301+ and check_issue .violatingEntity == violating_entity
302+ and check_issue .violatingPropertyValue == violation .value
303+ ):
253304 skip_requirement_check = True
254- logger .debug ("Skipping requirement check %s: %s" , requirementCheck .identifier ,
255- violation_message )
305+ logger .debug (
306+ "Skipping requirement check %s: %s" ,
307+ requirementCheck .identifier ,
308+ violation_message ,
309+ )
256310 break
257311 # if the check is not to be skipped, add the issue to the context
258312 if not skip_requirement_check :
@@ -261,7 +315,9 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
261315 check = requirementCheck ,
262316 violatingProperty = violating_property ,
263317 violatingEntity = violating_entity ,
264- violatingPropertyValue = violation .value )
318+ violatingPropertyValue = violation .value ,
319+ )
320+ logger .debug ("Added validation issue to the context: %s" , c )
265321 # if the fail fast mode is enabled, stop the validation after the first issue
266322 if shacl_context .fail_fast :
267323 break
@@ -279,7 +335,10 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
279335 shacl_context .validator .notify (RequirementCheckValidationEvent (
280336 EventType .REQUIREMENT_CHECK_VALIDATION_END ,
281337 requirementCheck , validation_result = False ))
282- logger .debug ("Added validation issue to the context: %s" , c )
338+ logger .debug (
339+ "Added failed check to the context: %s" ,
340+ requirementCheck .identifier ,
341+ )
283342
284343 # if the fail fast mode is enabled, stop the validation after the first failed check
285344 if shacl_context .fail_fast :
@@ -296,16 +355,30 @@ def __do_execute_check__(self, shacl_context: SHACLValidationContext):
296355 if requirementCheck .identifier not in failed_requirement_checks_notified :
297356 failed_requirement_checks_notified .append (requirementCheck .identifier )
298357 shacl_context .result ._add_executed_check (requirementCheck , True )
299- if requirementCheck .requirement .profile != shacl_context .target_profile and \
300- shacl_context .settings .disable_inherited_profiles_issue_reporting :
358+ if (
359+ requirementCheck .requirement .profile != shacl_context .target_profile
360+ and shacl_context .settings .disable_inherited_profiles_issue_reporting
361+ ):
301362 continue
302- shacl_context .validator .notify (RequirementCheckValidationEvent (
303- EventType .REQUIREMENT_CHECK_VALIDATION_END , requirementCheck , validation_result = True ))
304- logger .debug ("Added skipped check to the context: %s" , requirementCheck .identifier )
363+ shacl_context .validator .notify (
364+ RequirementCheckValidationEvent (
365+ EventType .REQUIREMENT_CHECK_VALIDATION_END ,
366+ requirementCheck ,
367+ validation_result = True ,
368+ )
369+ )
370+ logger .debug (
371+ "Added skipped check to the context: %s" ,
372+ requirementCheck .identifier ,
373+ )
305374
306375 logger .debug ("Remaining skipped checks: %r" , len (shacl_context .result .skipped_checks ))
307376 for requirementCheck in shacl_context .result .skipped_checks :
308- logger .debug ("Remaining skipped check: %r - %s" , requirementCheck .identifier , requirementCheck .name )
377+ logger .debug (
378+ "Remaining skipped check: %r - %s" ,
379+ requirementCheck .identifier ,
380+ requirementCheck .name ,
381+ )
309382 end_time = timer ()
310383 logger .debug (f"Execution time for parsing the validation result: { end_time - start_time } seconds" )
311384
0 commit comments