personal_knowledge_library 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of personal_knowledge_library might be problematic. Click here for more details.

Files changed (42) hide show
  1. knowledge/__init__.py +91 -0
  2. knowledge/base/__init__.py +22 -0
  3. knowledge/base/access.py +167 -0
  4. knowledge/base/entity.py +267 -0
  5. knowledge/base/language.py +27 -0
  6. knowledge/base/ontology.py +2734 -0
  7. knowledge/base/search.py +473 -0
  8. knowledge/base/tenant.py +192 -0
  9. knowledge/nel/__init__.py +11 -0
  10. knowledge/nel/base.py +495 -0
  11. knowledge/nel/engine.py +123 -0
  12. knowledge/ontomapping/__init__.py +667 -0
  13. knowledge/ontomapping/manager.py +320 -0
  14. knowledge/public/__init__.py +27 -0
  15. knowledge/public/cache.py +115 -0
  16. knowledge/public/helper.py +373 -0
  17. knowledge/public/relations.py +128 -0
  18. knowledge/public/wikidata.py +1324 -0
  19. knowledge/services/__init__.py +128 -0
  20. knowledge/services/asyncio/__init__.py +7 -0
  21. knowledge/services/asyncio/base.py +458 -0
  22. knowledge/services/asyncio/graph.py +1420 -0
  23. knowledge/services/asyncio/group.py +450 -0
  24. knowledge/services/asyncio/search.py +439 -0
  25. knowledge/services/asyncio/users.py +270 -0
  26. knowledge/services/base.py +533 -0
  27. knowledge/services/graph.py +1897 -0
  28. knowledge/services/group.py +819 -0
  29. knowledge/services/helper.py +142 -0
  30. knowledge/services/ontology.py +1234 -0
  31. knowledge/services/search.py +488 -0
  32. knowledge/services/session.py +444 -0
  33. knowledge/services/tenant.py +281 -0
  34. knowledge/services/users.py +445 -0
  35. knowledge/utils/__init__.py +10 -0
  36. knowledge/utils/graph.py +417 -0
  37. knowledge/utils/wikidata.py +197 -0
  38. knowledge/utils/wikipedia.py +175 -0
  39. personal_knowledge_library-3.0.0.dist-info/LICENSE +201 -0
  40. personal_knowledge_library-3.0.0.dist-info/METADATA +1163 -0
  41. personal_knowledge_library-3.0.0.dist-info/RECORD +42 -0
  42. personal_knowledge_library-3.0.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,667 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright © 2021-present Wacom. All rights reserved.
3
+ import enum
4
+ import json
5
+ from datetime import datetime
6
+ from pathlib import Path
7
+ from typing import Dict, Any, List, Optional, Set
8
+
9
+ import loguru
10
+ from rdflib import Graph, RDFS, URIRef
11
+
12
+ from knowledge.base.ontology import OntologyClassReference, OntologyPropertyReference, DataPropertyType
13
+ from knowledge.public.wikidata import WikidataClass, WikiDataAPIClient
14
+
15
+ # Classes
16
+ TOPIC_CLASS: str = "wacom:core#Topic"
17
+ # Constants
18
+ DBPEDIA_TYPES: str = "dbpedia_types"
19
+ WIKIDATA_TYPES: str = "wikidata_types"
20
+ OBJECT_PROPERTIES: str = "object_properties"
21
+ DATA_PROPERTIES: str = "data_properties"
22
+ DOMAIN_PROPERTIES: str = "domain"
23
+ CLASSES: str = "classes"
24
+ CONTEXT_NAME: str = "core"
25
+ CWD: Path = Path(__file__).parent
26
+ ontology_graph: Graph = Graph()
27
+ logger = loguru.logger
28
+ # Mapping configuration
29
+ superclasses_cache: Optional[Dict[str, WikidataClass]] = None
30
+ subclasses_cache: Optional[Dict[str, WikidataClass]] = None
31
+ superclasses_path: Optional[Path] = None
32
+ subclasses_path: Optional[Path] = None
33
+
34
+
35
+ def flatten(hierarchy: WikidataClass) -> Set[str]:
36
+ """
37
+ Flattens the hierarchy.
38
+
39
+ Parameters
40
+ ----------
41
+ hierarchy: WikidataClass
42
+ Hierarchy
43
+
44
+ Returns
45
+ -------
46
+ hierarchy: Set[str]
47
+ Hierarchy
48
+
49
+ """
50
+ hierarchy_set: Set[str] = {hierarchy.qid}
51
+ jobs: List[WikidataClass] = [hierarchy]
52
+ while len(jobs) > 0:
53
+ job: WikidataClass = jobs.pop()
54
+ hierarchy_set.add(job.qid)
55
+ for c in job.subclasses:
56
+ jobs.append(c)
57
+ return hierarchy_set
58
+
59
+
60
+ def subclasses_of(iri: str) -> List[str]:
61
+ """
62
+ Returns the subclasses of an ontology class.
63
+ Parameters
64
+ ----------
65
+ iri: str
66
+ Ontology class IRI.
67
+
68
+ Returns
69
+ -------
70
+ subclasses: List[str]
71
+ Subclasses of the ontology class.
72
+ """
73
+ sub_classes: List[str] = [str(s) for s, p, o in list(ontology_graph.triples((None, RDFS.subClassOf, URIRef(iri))))]
74
+ for sub_class in sub_classes:
75
+ sub_classes.extend(subclasses_of(sub_class))
76
+ return sub_classes
77
+
78
+
79
+ def is_iso_date(date_string: str) -> bool:
80
+ """
81
+ Checks if a date string is an ISO date.
82
+ Parameters
83
+ ----------
84
+ date_string: str
85
+ Date string.
86
+
87
+ Returns
88
+ -------
89
+ is_iso_date: bool
90
+ True if the date string is an ISO date, otherwise False.
91
+ """
92
+ try:
93
+ datetime.fromisoformat(date_string)
94
+ return True
95
+ except ValueError as _:
96
+ return False
97
+
98
+
99
+ class WikidataClassEncoder(json.JSONEncoder):
100
+ """
101
+ Wikidata Class encoder
102
+ ----------------------
103
+ This class encodes a Wikidata class to JSON.
104
+ """
105
+
106
+ def default(self, o):
107
+ if isinstance(o, WikidataClass):
108
+ return o.__dict__()
109
+ return json.JSONEncoder.default(self, o)
110
+
111
+
112
+ class ClassConfiguration:
113
+ """
114
+ Class configuration
115
+ -------------------
116
+ This class contains the configuration for a class.
117
+
118
+ Parameters
119
+ ----------
120
+ ontology_class: str
121
+ Ontology class
122
+ """
123
+
124
+ def __init__(self, ontology_class: str):
125
+ self.__ontology_class: str = ontology_class
126
+ self.__wikidata_classes: List[str] = []
127
+ self.__dbpedia_classes: List[str] = []
128
+
129
+ @property
130
+ def ontology_class(self) -> str:
131
+ """Ontology class."""
132
+ return self.__ontology_class
133
+
134
+ @property
135
+ def wikidata_classes(self) -> List[str]:
136
+ """Wikidata classes."""
137
+ return self.__wikidata_classes
138
+
139
+ @wikidata_classes.setter
140
+ def wikidata_classes(self, value: List[str]):
141
+ self.__wikidata_classes = value
142
+
143
+ @property
144
+ def dbpedia_classes(self) -> List[str]:
145
+ """DBpedia classes."""
146
+ return self.__dbpedia_classes
147
+
148
+ @dbpedia_classes.setter
149
+ def dbpedia_classes(self, value: List[str]):
150
+ self.__dbpedia_classes = value
151
+
152
+ @property
153
+ def concept_type(self) -> OntologyClassReference:
154
+ """Concept type."""
155
+ return OntologyClassReference.parse(self.__ontology_class)
156
+
157
+ def __str__(self):
158
+ return (
159
+ f"ClassConfiguration(ontology_class={self.__ontology_class}, "
160
+ f"wikidata_classes={self.__wikidata_classes}, dbpedia_classes={self.__dbpedia_classes})"
161
+ )
162
+
163
+
164
+ class PropertyType(enum.Enum):
165
+ """
166
+ Property type
167
+ """
168
+
169
+ DATA_PROPERTY = 0
170
+ OBJECT_PROPERTY = 1
171
+
172
+
173
+ class PropertyConfiguration:
174
+ """
175
+ Property configuration.
176
+ -----------------------
177
+ This class contains the configuration for a property.
178
+
179
+ Parameters
180
+ ----------
181
+ iri: str
182
+ The IRI of the property.
183
+ property_type: PropertyType
184
+ The property type.
185
+ pids: Optional[List[str]]
186
+ The list of property PIDs.
187
+ """
188
+
189
+ def __init__(self, iri: str, property_type: PropertyType, pids: Optional[List[str]] = None):
190
+ self.__iri: str = iri
191
+ self.__pids: List[str] = pids if pids else []
192
+ self.__property: PropertyType = property_type
193
+ self.__inverse: Optional[str] = None
194
+ self.__ranges: List[str] = []
195
+ self.__domains: List[str] = []
196
+
197
+ @property
198
+ def iri(self) -> str:
199
+ """IRI of the property."""
200
+ return self.__iri
201
+
202
+ @iri.setter
203
+ def iri(self, value: str):
204
+ self.__iri = value
205
+
206
+ @property
207
+ def inverse(self) -> Optional[str]:
208
+ """Inverse property."""
209
+ return self.__inverse
210
+
211
+ @inverse.setter
212
+ def inverse(self, value: str):
213
+ self.__inverse = value
214
+
215
+ @property
216
+ def type(self) -> PropertyType:
217
+ """Property type."""
218
+ return self.__property
219
+
220
+ @property
221
+ def pids(self) -> List[str]:
222
+ """List of property PIDs."""
223
+ return self.__pids
224
+
225
+ @property
226
+ def ranges(self) -> List[str]:
227
+ """List of ranges."""
228
+ return self.__ranges
229
+
230
+ @property
231
+ def domains(self) -> List[str]:
232
+ """List of domains."""
233
+ return self.__domains
234
+
235
+ def __str__(self):
236
+ return f"PropertyConfiguration(ontology_property={self.iri})"
237
+
238
+
239
+ class MappingConfiguration:
240
+ """
241
+ Mapping configuration
242
+ ---------------------
243
+ This class contains the configuration for the mapping.
244
+
245
+ """
246
+
247
+ def __init__(self):
248
+ self.__classes: List[ClassConfiguration] = []
249
+ self.__properties: List[PropertyConfiguration] = []
250
+ self.__index: Dict[str, int] = {}
251
+ self.__index_properties: Dict[str, List[int]] = {}
252
+ self.__index_iri: Dict[str, int] = {}
253
+ self.__direct_index: Dict[str, int] = {}
254
+
255
+ @property
256
+ def classes(self) -> List[ClassConfiguration]:
257
+ """List of classes."""
258
+ return self.__classes
259
+
260
+ @property
261
+ def properties(self) -> List[PropertyConfiguration]:
262
+ """List of properties."""
263
+ return self.__properties
264
+
265
+ def guess_classed(self, classes: List[str]) -> Optional[ClassConfiguration]:
266
+ """
267
+ Guesses the class from the label.
268
+ Parameters
269
+ ----------
270
+ classes: List[str]
271
+ The list of classes
272
+
273
+ Returns
274
+ -------
275
+ class: Optional[ClassConfiguration]
276
+ If a mapping exists, the class configuration, otherwise None.
277
+ """
278
+ for cls_name in classes:
279
+ if cls_name in self.__direct_index:
280
+ return self.__classes[self.__direct_index[cls_name]]
281
+ if cls_name in self.__index:
282
+ return self.__classes[self.__index[cls_name]]
283
+ return None
284
+
285
+ def guess_property(
286
+ self, property_pid: str, concept_type: OntologyClassReference
287
+ ) -> Optional[PropertyConfiguration]:
288
+ """
289
+ Guesses the property from the label.
290
+ Parameters
291
+ ----------
292
+ property_pid: str
293
+ PID of the property
294
+ concept_type: OntologyClassReference
295
+ The concept type.
296
+ Returns
297
+ -------
298
+ property_config: Optional[PropertyConfiguration]
299
+ If a mapping exists, the property configuration, otherwise None.
300
+ """
301
+ if property_pid in self.__index_properties:
302
+ for pid_idx in self.__index_properties[property_pid]:
303
+ prop_conf: PropertyConfiguration = self.__properties[pid_idx]
304
+ if concept_type.iri in prop_conf.domains:
305
+ return prop_conf
306
+ return None
307
+
308
+ def property_for(
309
+ self, class_ref: OntologyClassReference, property_type: Optional[PropertyType]
310
+ ) -> List[PropertyConfiguration]:
311
+ """
312
+ Returns the properties for a class.
313
+ Parameters
314
+ ----------
315
+ class_ref: OntologyClassReference
316
+ The class reference.
317
+ property_type: Optional[PropertyType]
318
+ The property type, if None, all properties are returned.
319
+ Returns
320
+ -------
321
+ properties: List[PropertyConfiguration]
322
+ The list of properties.
323
+ """
324
+ domain_classes: List[str] = [class_ref.iri]
325
+ domain_classes += subclasses_of(class_ref.iri)
326
+ domain_subclasses: Dict[str, List[str]] = {}
327
+ properties: List[PropertyConfiguration] = []
328
+ for prop_conf in self.properties:
329
+ for d in prop_conf.domains:
330
+ if d not in domain_subclasses:
331
+ domain_subclasses[d] = [d] + subclasses_of(d)
332
+ if class_ref.iri in domain_subclasses[d]:
333
+ if property_type is None or prop_conf.type == property_type:
334
+ properties.append(prop_conf)
335
+ return properties
336
+
337
+ def add_class(self, class_configuration: ClassConfiguration, subclasses: Dict[str, List[str]]):
338
+ """
339
+ Adds a class configuration.
340
+
341
+ Parameters
342
+ ----------
343
+ class_configuration: ClassConfiguration
344
+ The class configuration
345
+ subclasses: Dict[str, List[str]]
346
+ The subclasses
347
+ """
348
+ self.__classes.append(class_configuration)
349
+ class_idx: int = len(self.__classes) - 1
350
+ number_of_classes: int = len(class_configuration.wikidata_classes)
351
+ if number_of_classes > 0:
352
+ logger.info(f"Adding {number_of_classes} classes for {class_configuration.concept_type.iri}")
353
+ for cls_idx, c in enumerate(class_configuration.wikidata_classes):
354
+ if c in subclasses:
355
+ for subclass in subclasses[c]:
356
+ if subclass in self.__index:
357
+ logger.warning(f"Class {subclass} already exists in the index.")
358
+ class_config: ClassConfiguration = self.__classes[self.__index[subclass]]
359
+ logger.warning(f"Class {class_config.concept_type} "
360
+ f"is conflicting with {class_configuration.concept_type}.")
361
+ self.__index[subclass] = class_idx
362
+ self.__direct_index[c] = class_idx
363
+ else:
364
+ w_classes: Dict[str, WikidataClass] = WikiDataAPIClient.subclasses(c)
365
+ for subclass in w_classes.values():
366
+ for cls in flatten(subclass):
367
+ self.__index[cls] = class_idx
368
+
369
+ for c in class_configuration.dbpedia_classes:
370
+ self.__index[c] = len(self.__classes) - 1
371
+
372
+ def add_property(self, property_configuration: PropertyConfiguration):
373
+ """
374
+ Adds a property configuration.
375
+
376
+ Parameters
377
+ ----------
378
+ property_configuration: PropertyConfiguration
379
+ The property configuration
380
+ """
381
+ self.__properties.append(property_configuration)
382
+ for pid in property_configuration.pids:
383
+ idx: int = len(self.__properties) - 1
384
+ if pid not in self.__index_properties:
385
+ self.__index_properties[pid] = []
386
+ self.__index_properties[pid].append(idx)
387
+ self.__index_iri[property_configuration.iri] = idx
388
+
389
+ def property_for_iri(self, property_iri: str) -> PropertyConfiguration:
390
+ """
391
+ Returns the property configuration for an IRI.
392
+
393
+ Parameters
394
+ ----------
395
+ property_iri: str
396
+ The property IRI
397
+
398
+ Returns
399
+ -------
400
+ property: PropertyConfiguration
401
+ The property configuration
402
+
403
+ Raises
404
+ ------
405
+ ValueError
406
+ If the property is not found.
407
+ """
408
+ if property_iri not in self.__index_iri:
409
+ raise ValueError(f"Property {property_iri} not found.")
410
+ return self.__properties[self.__index_iri[property_iri]]
411
+
412
+ def check_data_property_range(self, property_type: OntologyPropertyReference, content: Optional[Any]) -> bool:
413
+ """
414
+ Checks if the content is in the range of the property.
415
+
416
+ Parameters
417
+ ----------
418
+ property_type: OntologyPropertyReference
419
+ The property type
420
+ content: Optional[Any]
421
+ The content
422
+
423
+ Returns
424
+ -------
425
+ evaluation: bool
426
+ True if the content is in the range, False otherwise.
427
+ """
428
+ if content is None:
429
+ return False
430
+ prop_config: Optional[PropertyConfiguration] = self.property_for_iri(property_type.iri)
431
+ if prop_config:
432
+ for r in prop_config.ranges:
433
+ if r == DataPropertyType.STRING.value:
434
+ return content is not None and isinstance(content, str)
435
+ if r == DataPropertyType.INTEGER.value:
436
+ return content is not None and isinstance(content, int)
437
+ if r == DataPropertyType.FLOAT.value:
438
+ return content is not None and isinstance(content, float)
439
+ if r == DataPropertyType.BOOLEAN.value:
440
+ return content is not None and isinstance(content, bool)
441
+ if r in {DataPropertyType.DATE.value, DataPropertyType.DATE_TIME.value}:
442
+ return content is not None and isinstance(content, str) and is_iso_date(content)
443
+ return True
444
+ return False
445
+
446
+ def check_object_property_range(
447
+ self,
448
+ property_type: OntologyPropertyReference,
449
+ source_type: OntologyClassReference,
450
+ target_type: OntologyClassReference,
451
+ ) -> bool:
452
+ """
453
+ Checks if the target is in the range of the property.
454
+ Parameters
455
+ ----------
456
+ property_type: OntologyPropertyReference
457
+ The property
458
+ source_type: OntologyClassReference
459
+ The concept type
460
+ target_type: OntologyClassReference
461
+ The target type
462
+
463
+ Returns
464
+ -------
465
+ valid: bool
466
+ True if the target is in the range, False otherwise.
467
+ """
468
+ prop_config: Optional[PropertyConfiguration] = self.property_for_iri(property_type.iri)
469
+ if prop_config:
470
+ if prop_config.type == PropertyType.OBJECT_PROPERTY:
471
+ if source_type.iri in prop_config.domains and target_type.iri in prop_config.ranges:
472
+ return True
473
+ return False
474
+ return False
475
+
476
+ def __str__(self):
477
+ return f"Mapping Configuration(#classes={len(self.__classes)}" f", #properties={len(self.__properties)})"
478
+
479
+
480
+ mapping_configuration: Optional[MappingConfiguration] = None
481
+
482
+
483
+ def build_configuration(mapping: Dict[str, Any], subclasses: Dict[str, List[str]]) -> MappingConfiguration:
484
+ """
485
+ Builds the configuration from the mapping file.
486
+ Parameters
487
+ ----------
488
+ mapping: Dict[str, Any]
489
+ The mapping file
490
+ subclasses: Dict[str, List[str]]
491
+ The subclasses
492
+
493
+ Returns
494
+ -------
495
+ conf: MappingConfiguration
496
+ The mapping configuration
497
+ """
498
+ conf: MappingConfiguration = MappingConfiguration()
499
+ configuration_classes: int = len(mapping["classes"])
500
+ logger.debug(f"Adding {configuration_classes} classes to the mapping configuration")
501
+ for c, c_conf in mapping["classes"].items():
502
+ class_config: ClassConfiguration = ClassConfiguration(c)
503
+ class_config.dbpedia_classes = c_conf[DBPEDIA_TYPES]
504
+ class_config.wikidata_classes = c_conf[WIKIDATA_TYPES]
505
+ conf.add_class(class_config, subclasses)
506
+ dataproperty_count: int = len(mapping["data_properties"])
507
+ logger.debug(f"Adding {dataproperty_count} data properties to the mapping configuration")
508
+ for p, p_conf in mapping["data_properties"].items():
509
+ property_config: PropertyConfiguration = PropertyConfiguration(
510
+ p, PropertyType.DATA_PROPERTY, p_conf["wikidata_types"]
511
+ )
512
+ if "ranges" in p_conf:
513
+ for ra in p_conf["ranges"]:
514
+ property_config.ranges.append(ra)
515
+ property_config.ranges.extend(subclasses_of(ra))
516
+ if "domains" in p_conf:
517
+ for do in p_conf["domains"]:
518
+ property_config.domains.append(do)
519
+ property_config.domains.extend(subclasses_of(do))
520
+
521
+ conf.add_property(property_config)
522
+ object_property_count: int = len(mapping["object_properties"])
523
+ logger.debug(f"Adding {object_property_count} object properties to the mapping configuration")
524
+ for p, p_conf in mapping["object_properties"].items():
525
+ property_config: PropertyConfiguration = PropertyConfiguration(
526
+ p, PropertyType.OBJECT_PROPERTY, p_conf["wikidata_types"]
527
+ )
528
+ if "ranges" in p_conf:
529
+ for ra in p_conf["ranges"]:
530
+ property_config.ranges.append(ra)
531
+ property_config.ranges.extend(subclasses_of(ra))
532
+ if "domains" in p_conf:
533
+ for do in p_conf["domains"]:
534
+ property_config.domains.append(do)
535
+ property_config.domains.extend(subclasses_of(do))
536
+ if "inverse" in p_conf:
537
+ property_config.inverse = p_conf["inverse"]
538
+ conf.add_property(property_config)
539
+ return conf
540
+
541
+
542
+ def update_superclass_cache(path: Path):
543
+ """
544
+ Updates the taxonomy cache.
545
+
546
+ Parameters
547
+ ----------
548
+ path: Path
549
+ The path to the cache file.
550
+ """
551
+ with open(path, "w", encoding="uft-8") as fp_taxonomy_write:
552
+ fp_taxonomy_write.write(json.dumps(superclasses_cache, indent=2, cls=WikidataClassEncoder))
553
+
554
+
555
+ def register_ontology(rdf_str: str):
556
+ """
557
+ Registers the ontology.
558
+ Parameters
559
+ ----------
560
+ rdf_str: str
561
+ The ontology in RDF/XML format.
562
+ """
563
+ ontology_graph.parse(data=rdf_str, format="xml")
564
+
565
+
566
+ def superclass_path_from(configuration_path: Path) -> Path:
567
+ """
568
+ Returns the path to the superclass cache file.
569
+
570
+ Parameters
571
+ ----------
572
+ configuration_path: Path
573
+ The path to the configuration file.
574
+
575
+ Returns
576
+ -------
577
+ path: Path
578
+ The path to the superclass cache file.
579
+ """
580
+ return configuration_path.parent / "superclasses.json"
581
+
582
+
583
+ def subclass_path_from(path: Path):
584
+ """
585
+ Returns the path to the subclass cache file.
586
+
587
+ Parameters
588
+ ----------
589
+ path: Path
590
+ The path to the configuration file.
591
+
592
+ Returns
593
+ -------
594
+ subclass_path: Path
595
+ The path to the subclass cache file.
596
+ """
597
+ return path.parent / "subclasses.json"
598
+
599
+
600
+ def load_configuration(configuration: Path):
601
+ """
602
+ Loads the configuration.
603
+
604
+ Raises
605
+ ------
606
+ ValueError
607
+ If the configuration file is not found.
608
+ """
609
+ global mapping_configuration, superclasses_cache, subclasses_cache, superclasses_path, subclasses_path
610
+ subclasses_path = subclass_path_from(configuration)
611
+ superclasses_path = superclass_path_from(configuration)
612
+ if configuration.exists():
613
+ with configuration.open("r", encoding="utf-8") as fp_configuration:
614
+ configuration = json.loads(fp_configuration.read())
615
+ subclasses: Dict[str, List[str]] = {}
616
+ if subclasses_path.exists():
617
+ with subclasses_path.open("r", encoding="utf-8") as fp_sub:
618
+ subclasses = json.loads(fp_sub.read())
619
+ mapping_configuration = build_configuration(configuration, subclasses)
620
+ else:
621
+ raise ValueError(f"Configuration file {configuration} not found.")
622
+
623
+
624
+ def get_mapping_configuration() -> MappingConfiguration:
625
+ """
626
+ Returns the mapping configuration.
627
+
628
+ Returns
629
+ -------
630
+ mapping_configuration: MappingConfiguration
631
+ The mapping configuration
632
+ """
633
+ if mapping_configuration is None:
634
+ raise ValueError("Please load configuration")
635
+ return mapping_configuration
636
+
637
+
638
+ def save_superclasses_cache(path: Path):
639
+ """
640
+ Saves the taxonomy cache.
641
+
642
+ Parameters
643
+ ----------
644
+ path: Path
645
+ The path to the cache file.
646
+ """
647
+ global superclasses_cache
648
+ if superclasses_cache is None:
649
+ return
650
+ with open(path, "w", encoding="utf-8") as fp_taxonomy_write:
651
+ fp_taxonomy_write.write(json.dumps(superclasses_cache, indent=2, cls=WikidataClassEncoder))
652
+
653
+
654
+ def save_subclasses_cache(path: Path):
655
+ """
656
+ Saves the taxonomy cache.
657
+
658
+ Parameters
659
+ ----------
660
+ path: Path
661
+ The path to the cache file.
662
+ """
663
+ global subclasses_cache
664
+ if subclasses_cache is None:
665
+ return
666
+ with open(path, "w", encoding="utf-8") as fp_taxonomy_write:
667
+ fp_taxonomy_write.write(json.dumps(subclasses_cache, indent=2, cls=WikidataClassEncoder))