Coverage for python/pyshacl_turbo/shape.py: 100.0%

59 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-16 12:25 +0000

1"""RDFLib-facing shape inspection; targeting executes in Rust.""" 

2 

3import logging 

4from decimal import Decimal 

5 

6from rdflib.namespace import RDF, RDFS, SH 

7 

8from .target_data import prepare_target_data 

9 

10 

11class Shape: 

12 def __init__(self, sg, node, p=False, path=None, logger=None): 

13 self.sg = sg 1efhijgbcd

14 self.node = node 1efhijgbcd

15 self._p = p 1efhijgbcd

16 self._path = path 1efhijgbcd

17 self._advanced = False 1efhijgbcd

18 self.logger = logger or logging.getLogger(__name__) 1efhijgbcd

19 

20 @property 

21 def is_property_shape(self): 

22 return self._p 1bc

23 

24 @property 

25 def deactivated(self): 

26 return bool(self.sg.graph.value(self.node, SH.deactivated)) 1bc

27 

28 @property 

29 def severity(self): 

30 return self.sg.graph.value(self.node, SH.severity, default=SH.Violation) 1d

31 

32 @property 

33 def message(self): 

34 return iter(set(self.objects(SH.message))) 1d

35 

36 @property 

37 def name(self): 

38 return iter(set(self.objects(SH.name))) 1d

39 

40 @property 

41 def description(self): 

42 return iter(set(self.objects(SH.description))) 1d

43 

44 @property 

45 def order(self): 

46 return Decimal(str(self.sg.graph.value(self.node, SH.order, default=0))) 1d

47 

48 def objects(self, predicate): 

49 return self.sg.objects(self.node, predicate) 1bcd

50 

51 def path(self): 

52 return self._path if self._p else None 1bc

53 

54 def property_shapes(self): 

55 return self.objects(SH.property) 1d

56 

57 def get_other_shape(self, node): 

58 return self.sg.lookup_shape_from_node(node) 1d

59 

60 def target_nodes(self): 

61 return self.objects(SH.targetNode) 1bc

62 

63 def target_classes(self): 

64 return self.objects(SH.targetClass) 1bc

65 

66 def target_objects_of(self): 

67 return self.objects(SH.targetObjectsOf) 1bc

68 

69 def target_subjects_of(self): 

70 return self.objects(SH.targetSubjectsOf) 1bc

71 

72 def implicit_class_targets(self): 

73 classes = set(self.sg.graph.subjects(RDFS.subClassOf, RDFS.Class)) | {RDFS.Class} 1bc

74 return [self.node] if classes.intersection(self.objects(RDF.type)) else [] 1bc

75 

76 def target(self): 

77 return ( 1bc

78 self.target_nodes(), 

79 self.target_classes(), 

80 self.implicit_class_targets(), 

81 self.target_objects_of(), 

82 self.target_subjects_of(), 

83 ) 

84 

85 def set_advanced(self, value): 

86 self._advanced = bool(value) 1efg

87 

88 def focus_nodes(self, data_graph, debug=False): 

89 data = prepare_target_data(data_graph) 1efhijgbcd

90 return data._focus_nodes(self.sg._compile(), self.node, self._advanced) 1efhijgbcd