Coverage for heritrace/utils/draft_labels.py: 99%

69 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-13 22:01 +0000

1# SPDX-FileCopyrightText: 2026 Arcangelo Massari <arcangelo.massari@unibo.it> 

2# 

3# SPDX-License-Identifier: ISC 

4 

5from uuid import uuid4 

6 

7from rdflib import RDF, Graph, Literal, URIRef 

8 

9from heritrace.extensions import get_form_fields 

10from heritrace.sparql import select_results 

11from heritrace.utils.datatypes import determine_datatype 

12from heritrace.utils.display_rules_utils import find_matching_rule 

13from heritrace.utils.shacl_utils import find_matching_form_field 

14from heritrace.utils.uri_utils import is_valid_url 

15 

16 

17def add_draft_entity(graph: Graph, entity: dict) -> URIRef: 

18 if entity.get("is_existing_entity"): 

19 uri = URIRef(entity["entity_uri"]) 

20 if "properties" not in entity: 

21 return uri 

22 else: 

23 uri = URIRef(f"urn:heritrace:draft:{uuid4()}") 

24 graph.add((uri, RDF.type, URIRef(entity["entity_type"]))) 

25 form_fields = get_form_fields() 

26 key = find_matching_form_field( 

27 entity["entity_type"], entity["entity_shape"], form_fields 

28 ) 

29 for predicate, raw_values in entity["properties"].items(): 

30 values = raw_values if isinstance(raw_values, list) else [raw_values] 

31 for value in values: 

32 if isinstance(value, dict): 

33 node = add_draft_entity(graph, value) 

34 elif is_valid_url(str(value)): 

35 node = URIRef(value) 

36 else: 

37 datatypes = [] 

38 if key and predicate in form_fields[key]: 

39 fields = form_fields[key][predicate] 

40 if fields and "datatypes" in fields[0]: 

41 datatypes = fields[0]["datatypes"] 

42 node = Literal( 

43 value, datatype=determine_datatype(str(value), datatypes) 

44 ) 

45 graph.add((uri, URIRef(predicate), node)) 

46 return uri 

47 

48 

49def relation_display_query(entry: dict) -> str | None: 

50 parent_rule = find_matching_rule(entry["parent_class"], entry["parent_shape"]) 

51 if not parent_rule or "displayProperties" not in parent_rule: 

52 return None 

53 for prop in parent_rule["displayProperties"]: 

54 if prop.get("property") != entry["predicate"]: 

55 continue 

56 candidates = [prop] 

57 if "displayRules" in prop: 

58 candidates = prop["displayRules"] 

59 for rule in candidates: 

60 if "shape" in rule and rule["shape"] != entry["entity"]["entity_shape"]: 

61 continue 

62 if "fetchValueFromQuery" in rule: 

63 return rule["fetchValueFromQuery"] 

64 return None 

65 

66 

67def draft_label(entry: dict) -> str | None: 

68 graph = Graph() 

69 entity = entry["entity"] 

70 uri = add_draft_entity(graph, entity) 

71 parent = URIRef(f"urn:heritrace:draft:{uuid4()}") 

72 graph.add((parent, RDF.type, URIRef(entry["parent_class"]))) 

73 graph.add((parent, URIRef(entry["predicate"]), uri)) 

74 query = relation_display_query(entry) 

75 if query is None: 

76 rule = find_matching_rule(entity["entity_type"], entity["entity_shape"]) 

77 if rule and "fetchUriDisplay" in rule: 

78 query = rule["fetchUriDisplay"] 

79 if query is None: 

80 return None 

81 query = ( 

82 query.replace("[[subject]]", parent.n3()) 

83 .replace("[[value]]", uri.n3()) 

84 .replace("[[uri]]", uri.n3()) 

85 ) 

86 for row in select_results(graph.query(query)): 

87 if row[0] is not None: 

88 label = str(row[0]).strip() 

89 if label and "urn:heritrace:draft:" not in label: 

90 return label 

91 return None