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,1897 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright © 2021-present Wacom. All rights reserved.
3
+ import enum
4
+ import gzip
5
+ import json
6
+ import os
7
+ import urllib
8
+ from pathlib import Path
9
+ from typing import Any, Optional, List, Dict, Tuple, Literal
10
+ from urllib.parse import urlparse
11
+
12
+ import requests
13
+ from requests import Response
14
+ from requests.adapters import HTTPAdapter
15
+ from urllib3 import Retry
16
+
17
+ from knowledge.base.entity import (
18
+ DATA_PROPERTIES_TAG,
19
+ TYPE_TAG,
20
+ LABELS_TAG,
21
+ IS_MAIN_TAG,
22
+ RELATIONS_TAG,
23
+ LOCALE_TAG,
24
+ EntityStatus,
25
+ Label,
26
+ URIS_TAG,
27
+ FORCE_TAG,
28
+ URI_TAG,
29
+ )
30
+ from knowledge.base.language import LocaleCode
31
+ from knowledge.base.ontology import (
32
+ DataProperty,
33
+ OntologyPropertyReference,
34
+ ThingObject,
35
+ OntologyClassReference,
36
+ ObjectProperty,
37
+ EN_US,
38
+ )
39
+ from knowledge.services import (
40
+ AUTHORIZATION_HEADER_FLAG,
41
+ APPLICATION_JSON_HEADER,
42
+ RELATION_TAG,
43
+ TARGET,
44
+ ACTIVATION_TAG,
45
+ PREDICATE,
46
+ OBJECT,
47
+ SUBJECT,
48
+ LIMIT_PARAMETER,
49
+ ESTIMATE_COUNT,
50
+ VISIBILITY_TAG,
51
+ NEXT_PAGE_ID_TAG,
52
+ LISTING,
53
+ TOTAL_COUNT,
54
+ SEARCH_TERM,
55
+ LANGUAGE_PARAMETER,
56
+ TYPES_PARAMETER,
57
+ LIMIT,
58
+ VALUE,
59
+ LITERAL_PARAMETER,
60
+ SEARCH_PATTERN_PARAMETER,
61
+ SUBJECT_URI,
62
+ RELATION_URI,
63
+ OBJECT_URI,
64
+ DEFAULT_TIMEOUT,
65
+ IS_OWNER_PARAM,
66
+ PRUNE_PARAM,
67
+ STATUS_FORCE_LIST,
68
+ DEFAULT_MAX_RETRIES,
69
+ DEFAULT_BACKOFF_FACTOR,
70
+ ENTITIES_TAG,
71
+ NEL_PARAM,
72
+ )
73
+ from knowledge.services.base import (
74
+ WacomServiceAPIClient,
75
+ WacomServiceException,
76
+ USER_AGENT_HEADER_FLAG,
77
+ CONTENT_TYPE_HEADER_FLAG,
78
+ handle_error,
79
+ )
80
+ from knowledge.services.helper import split_updates, entity_payload
81
+ from knowledge.services.users import UserRole
82
+
83
+ MIME_TYPE: Dict[str, str] = {".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png"}
84
+
85
+
86
+ # ------------------------------- Enum ---------------------------------------------------------------------------------
87
+ class SearchPattern(enum.Enum):
88
+ """
89
+ SearchPattern
90
+ -------------
91
+ Different search pattern for literal search.
92
+ """
93
+
94
+ REGEX = "regex"
95
+ """Regular expression search pattern."""
96
+ GT = "gt"
97
+ """Greater than search pattern."""
98
+ GTE = "gte"
99
+ """Greater than or equal search pattern."""
100
+ LT = "lt"
101
+ """Less than search pattern."""
102
+ LTE = "lte"
103
+ """Less than or equal search pattern."""
104
+ EQ = "eq"
105
+ """Equal search pattern."""
106
+ RANGE = "range"
107
+ """Range search pattern."""
108
+
109
+
110
+ class Visibility(enum.Enum):
111
+ """
112
+ Visibility
113
+ ----------
114
+ Visibility of an entity.
115
+ The visibility of an entity determines who can see the entity.
116
+ """
117
+
118
+ PRIVATE = "Private"
119
+ """Only the owner of the entity can see the entity."""
120
+ PUBLIC = "Public"
121
+ """Everyone in the tenant can see the entity."""
122
+ SHARED = "Shared"
123
+ """Everyone who joined the group can see the entity."""
124
+
125
+
126
+ # -------------------------------------------- Service API Client ------------------------------------------------------
127
+ class WacomKnowledgeService(WacomServiceAPIClient):
128
+ """
129
+ WacomKnowledgeService
130
+ ---------------------
131
+ Client for the Semantic Ink Private knowledge system.
132
+
133
+ Operations for entities:
134
+ - Creation of entities
135
+ - Update of entities
136
+ - Deletion of entities
137
+ - Listing of entities
138
+
139
+ Parameters
140
+ ----------
141
+ application_name: str
142
+ Name of the application using the service
143
+ service_url: str
144
+ URL of the service
145
+ service_endpoint: str
146
+ Base endpoint
147
+ """
148
+
149
+ USER_ENDPOINT: str = "user"
150
+ ENTITY_ENDPOINT: str = "entity"
151
+ ENTITY_BULK_ENDPOINT: str = "entity/bulk"
152
+ ENTITY_IMAGE_ENDPOINT: str = "entity/image/"
153
+ ACTIVATIONS_ENDPOINT: str = "entity/activations"
154
+ LISTING_ENDPOINT: str = "entity/types"
155
+ RELATION_ENDPOINT: str = "entity/{}/relation"
156
+ RELATIONS_ENDPOINT: str = "entity/{}/relations"
157
+ SEARCH_LABELS_ENDPOINT: str = "semantic-search/labels"
158
+ SEARCH_TYPES_ENDPOINT: str = "semantic-search/types"
159
+ SEARCH_LITERALS_ENDPOINT: str = "semantic-search/literal"
160
+ SEARCH_DESCRIPTION_ENDPOINT: str = "semantic-search/description"
161
+ SEARCH_RELATION_ENDPOINT: str = "semantic-search/relation"
162
+ ONTOLOGY_UPDATE_ENDPOINT: str = "ontology-update"
163
+ IMPORT_ENTITIES_ENDPOINT: str = "import"
164
+ REBUILD_VECTOR_SEARCH_INDEX: str = "vector-search/rebuild"
165
+ REBUILD_NEL_INDEX: str = "nel/rebuild"
166
+
167
+ def __init__(
168
+ self,
169
+ application_name: str = "Knowledge Client",
170
+ service_url: str = WacomServiceAPIClient.SERVICE_URL,
171
+ service_endpoint: str = "graph/v1",
172
+ ):
173
+ super().__init__(application_name, service_url, service_endpoint)
174
+
175
+ def entity(
176
+ self,
177
+ uri: str,
178
+ auth_key: Optional[str] = None,
179
+ timeout: int = DEFAULT_TIMEOUT,
180
+ max_retries: int = DEFAULT_MAX_RETRIES,
181
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
182
+ ) -> ThingObject:
183
+ """
184
+ Retrieve entity information from personal knowledge, using the URI as identifier.
185
+
186
+ **Remark:** Object properties (relations) must be requested separately.
187
+
188
+ Parameters
189
+ ----------
190
+ uri: str
191
+ URI of entity
192
+ auth_key: Optional[str]
193
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
194
+ timeout: int
195
+ Timeout for the request (default: 60 seconds)
196
+ max_retries: int
197
+ Maximum number of retries (default: 3)
198
+ backoff_factor: float
199
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
200
+ second try without a delay) (default: 0.1)
201
+
202
+ Returns
203
+ -------
204
+ thing: ThingObject
205
+ Entity with is type URI, description, an image/icon, and tags (labels).
206
+
207
+ Raises
208
+ ------
209
+ WacomServiceException
210
+ If the graph service returns an error code or the entity is not found in the knowledge graph
211
+ """
212
+ if auth_key is None:
213
+ auth_key, _ = self.handle_token()
214
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{uri}"
215
+ headers: Dict[str, str] = {
216
+ USER_AGENT_HEADER_FLAG: self.user_agent,
217
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
218
+ }
219
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
220
+ with requests.Session() as session:
221
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
222
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
223
+ response: Response = session.get(url, headers=headers, timeout=timeout, verify=self.verify_calls)
224
+ if response.ok:
225
+ e: Dict[str, Any] = response.json()
226
+ pref_label: List[Label] = []
227
+ aliases: List[Label] = []
228
+ # Extract labels and alias
229
+ for label in e[LABELS_TAG]:
230
+ if label[IS_MAIN_TAG]: # Labels
231
+ pref_label.append(Label.create_from_dict(label))
232
+ else: # Alias
233
+ aliases.append(Label.create_from_dict(label))
234
+ thing: ThingObject = ThingObject.from_dict(e)
235
+ return thing
236
+ raise handle_error(f"Retrieving of entity content failed. URI:={uri}.", response)
237
+
238
+ def delete_entities(
239
+ self,
240
+ uris: List[str],
241
+ force: bool = False,
242
+ auth_key: Optional[str] = None,
243
+ timeout: int = DEFAULT_TIMEOUT,
244
+ max_retries: int = DEFAULT_MAX_RETRIES,
245
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
246
+ ):
247
+ """
248
+ Delete a list of entities.
249
+
250
+ Parameters
251
+ ----------
252
+ uris: List[str]
253
+ List of URI of entities. **Remark:** More than 100 entities are not possible in one request
254
+ force: bool
255
+ Force deletion process
256
+ auth_key: Optional[str] [default:= None]
257
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
258
+ timeout: int
259
+ Timeout for the request (default: 60 seconds)
260
+ max_retries: int
261
+ Maximum number of retries
262
+ backoff_factor: float
263
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
264
+ second try without a delay)
265
+
266
+ Raises
267
+ ------
268
+ WacomServiceException
269
+ If the graph service returns an error code
270
+ ValueError
271
+ If more than 100 entities are given
272
+ """
273
+ if len(uris) > 100:
274
+ raise ValueError("Please delete less than 100 entities.")
275
+ if auth_key is None:
276
+ auth_key, _ = self.handle_token()
277
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}"
278
+ headers: Dict[str, str] = {
279
+ USER_AGENT_HEADER_FLAG: self.user_agent,
280
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
281
+ }
282
+ params: Dict[str, Any] = {URIS_TAG: uris, FORCE_TAG: force}
283
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
284
+ with requests.Session() as session:
285
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
286
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
287
+ response: Response = session.delete(
288
+ url, headers=headers, params=params, timeout=timeout, verify=self.verify_calls
289
+ )
290
+ if not response.ok:
291
+ raise handle_error("Deletion of entities failed.", response)
292
+
293
+ def delete_entity(
294
+ self,
295
+ uri: str,
296
+ force: bool = False,
297
+ auth_key: Optional[str] = None,
298
+ timeout: int = DEFAULT_TIMEOUT,
299
+ max_retries: int = DEFAULT_MAX_RETRIES,
300
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
301
+ ):
302
+ """
303
+ Deletes an entity.
304
+
305
+ Parameters
306
+ ----------
307
+ uri: str
308
+ URI of entity
309
+ force: bool
310
+ Force deletion process
311
+ auth_key: Optional[str]
312
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
313
+ timeout: int
314
+ Timeout for the request (default: 60 seconds)
315
+ max_retries: int
316
+ Maximum number of retries
317
+ backoff_factor: float
318
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
319
+ second try without a delay)
320
+
321
+ Raises
322
+ ------
323
+ WacomServiceException
324
+ If the graph service returns an error code
325
+ """
326
+ if auth_key is None:
327
+ auth_key, _ = self.handle_token()
328
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{uri}"
329
+ headers: Dict[str, str] = {
330
+ USER_AGENT_HEADER_FLAG: self.user_agent,
331
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
332
+ }
333
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
334
+ with requests.Session() as session:
335
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
336
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
337
+ response: Response = session.delete(
338
+ url, headers=headers, params={FORCE_TAG: force}, timeout=timeout, verify=self.verify_calls
339
+ )
340
+ if not response.ok:
341
+ raise handle_error(f"Deletion of entity (URI:={uri}) failed.", response)
342
+
343
+ def exists(
344
+ self,
345
+ uri: str,
346
+ auth_key: Optional[str] = None,
347
+ timeout: int = DEFAULT_TIMEOUT,
348
+ max_retries: int = DEFAULT_MAX_RETRIES,
349
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
350
+ ) -> bool:
351
+ """
352
+ Check if entity exists in knowledge graph.
353
+
354
+ Parameters
355
+ ----------
356
+ uri: str -
357
+ URI for entity
358
+ auth_key: Optional[str]
359
+ Auth key from user
360
+ timeout: int
361
+ Timeout for the request (default: 60 seconds)
362
+ max_retries: int
363
+ Maximum number of retries (default: 3)
364
+ backoff_factor: float
365
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
366
+ second try without a delay) (default: 0.1)
367
+
368
+ Returns
369
+ -------
370
+ flag: bool
371
+ Flag if entity does exist
372
+ """
373
+ try:
374
+ obj: ThingObject = self.entity(
375
+ uri, auth_key=auth_key, timeout=timeout, max_retries=max_retries, backoff_factor=backoff_factor
376
+ )
377
+ return obj is not None
378
+ except WacomServiceException:
379
+ return False
380
+
381
+ @staticmethod
382
+ def __entity__(entity: ThingObject):
383
+ return entity_payload(entity)
384
+
385
+ def create_entity_bulk(
386
+ self,
387
+ entities: List[ThingObject],
388
+ batch_size: int = 10,
389
+ ignore_images: bool = False,
390
+ auth_key: Optional[str] = None,
391
+ timeout: int = DEFAULT_TIMEOUT,
392
+ max_retries: int = DEFAULT_MAX_RETRIES,
393
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
394
+ ) -> List[ThingObject]:
395
+ """
396
+ Creates entity in graph.
397
+
398
+ Parameters
399
+ ----------
400
+ entities: List[ThingObject]
401
+ Entities
402
+ batch_size: int
403
+ Batch size
404
+ ignore_images: bool
405
+ Ignore images
406
+ auth_key: Optional[str]
407
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
408
+ timeout: int
409
+ Timeout for the request (default: 60 seconds).
410
+ max_retries: int
411
+ Maximum number of retries
412
+ backoff_factor: float
413
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
414
+ second try without a delay)
415
+
416
+ Returns
417
+ -------
418
+ things: List[ThingObject]
419
+ List of entities with URI
420
+
421
+ Raises
422
+ ------
423
+ WacomServiceException
424
+ If the graph service returns an error code
425
+ """
426
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_BULK_ENDPOINT}"
427
+ # Header info
428
+ headers: Dict[str, str] = {
429
+ USER_AGENT_HEADER_FLAG: self.user_agent,
430
+ CONTENT_TYPE_HEADER_FLAG: APPLICATION_JSON_HEADER,
431
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
432
+ }
433
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
434
+ with requests.Session() as session:
435
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
436
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
437
+ payload: List[Dict[str, Any]] = [WacomKnowledgeService.__entity__(e) for e in entities]
438
+ for bulk_idx in range(0, len(entities), batch_size):
439
+ bulk = payload[bulk_idx : bulk_idx + batch_size]
440
+ response: Response = session.post(
441
+ url, json=bulk, headers=headers, timeout=timeout, verify=self.verify_calls
442
+ )
443
+ if response.ok:
444
+ response_dict: Dict[str, Any] = response.json()
445
+
446
+ for idx, uri in enumerate(response_dict[URIS_TAG]):
447
+ if (
448
+ entities[bulk_idx + idx].image is not None
449
+ and entities[bulk_idx + idx].image != ""
450
+ and not ignore_images
451
+ ):
452
+ self.set_entity_image_url(uri, entities[bulk_idx + idx].image, auth_key=auth_key)
453
+ entities[bulk_idx + idx].uri = response_dict[URIS_TAG][idx]
454
+ else:
455
+ raise handle_error("Pushing entity failed.", response)
456
+ return entities
457
+
458
+ def create_entity(
459
+ self,
460
+ entity: ThingObject,
461
+ ignore_image: bool = False,
462
+ auth_key: Optional[str] = None,
463
+ max_retries: int = DEFAULT_MAX_RETRIES,
464
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
465
+ timeout: int = DEFAULT_TIMEOUT,
466
+ ) -> str:
467
+ """
468
+ Creates entity in graph.
469
+
470
+ Parameters
471
+ ----------
472
+ entity: ThingObject
473
+ Entity object that needs to be created
474
+ ignore_image: bool [default:= False]
475
+ Ignore image.
476
+ auth_key: Optional[str]
477
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
478
+ max_retries: int [default:= 3]
479
+ Maximum number of retries
480
+ backoff_factor: float [default:= 0.1]
481
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
482
+ second try without a delay)
483
+ timeout: int [default:= 5]
484
+ Timeout for the request
485
+ Returns
486
+ -------
487
+ uri: str
488
+ URI of entity
489
+
490
+ Raises
491
+ ------
492
+ WacomServiceException
493
+ If the graph service returns an error code
494
+ """
495
+ if auth_key is None:
496
+ auth_key, _ = self.handle_token()
497
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}"
498
+ # Header info
499
+ headers: Dict[str, str] = {
500
+ USER_AGENT_HEADER_FLAG: self.user_agent,
501
+ CONTENT_TYPE_HEADER_FLAG: APPLICATION_JSON_HEADER,
502
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
503
+ }
504
+ payload: Dict[str, Any] = WacomKnowledgeService.__entity__(entity)
505
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
506
+ with requests.Session() as session:
507
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
508
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
509
+ response: Response = session.post(
510
+ url, json=payload, headers=headers, verify=self.verify_calls, timeout=timeout
511
+ )
512
+
513
+ if response.ok and not ignore_image:
514
+ uri: str = response.json()[URI_TAG]
515
+ # Set image
516
+ try:
517
+ if entity.image is not None and entity.image.startswith("file:"):
518
+ p = urlparse(entity.image)
519
+ self.set_entity_image_local(uri, Path(p.path), auth_key=auth_key)
520
+ elif entity.image is not None and entity.image != "":
521
+ self.set_entity_image_url(uri, entity.image, auth_key=auth_key)
522
+ except WacomServiceException as _:
523
+ pass
524
+ if response.ok:
525
+ uri: str = response.json()[URI_TAG]
526
+ return uri
527
+ raise handle_error("Pushing entity failed.", response)
528
+
529
+ def update_entity(
530
+ self,
531
+ entity: ThingObject,
532
+ auth_key: Optional[str] = None,
533
+ timeout: int = DEFAULT_TIMEOUT,
534
+ max_retries: int = DEFAULT_MAX_RETRIES,
535
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
536
+ ):
537
+ """
538
+ Updates entity in graph.
539
+
540
+ Parameters
541
+ ----------
542
+ entity: ThingObject
543
+ entity object
544
+ auth_key: Optional[str]
545
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
546
+ timeout: int
547
+ Timeout for the request (default: 60 seconds)
548
+ max_retries: int
549
+ Maximum number of retries
550
+ backoff_factor: float
551
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
552
+ second try without a delay)
553
+
554
+ Raises
555
+ ------
556
+ WacomServiceException
557
+ If the graph service returns an error code
558
+ """
559
+ if auth_key is None:
560
+ auth_key, _ = self.handle_token()
561
+ uri: str = entity.uri
562
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{uri}"
563
+ # Header info
564
+ headers: dict = {
565
+ USER_AGENT_HEADER_FLAG: self.user_agent,
566
+ CONTENT_TYPE_HEADER_FLAG: APPLICATION_JSON_HEADER,
567
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
568
+ }
569
+ payload: Dict[str, Any] = WacomKnowledgeService.__entity__(entity)
570
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
571
+ with requests.Session() as session:
572
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
573
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
574
+ response: Response = session.patch(
575
+ url, json=payload, headers=headers, timeout=timeout, verify=self.verify_calls
576
+ )
577
+ if not response.ok:
578
+ raise handle_error("Updating entity failed.", response)
579
+
580
+ def relations(
581
+ self,
582
+ uri: str,
583
+ auth_key: Optional[str] = None,
584
+ timeout: int = DEFAULT_TIMEOUT,
585
+ max_retries: int = DEFAULT_MAX_RETRIES,
586
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
587
+ ) -> Dict[OntologyPropertyReference, ObjectProperty]:
588
+ """
589
+ Retrieve the relations (object properties) of an entity.
590
+
591
+ Parameters
592
+ ----------
593
+ uri: str
594
+ Entity URI of the source
595
+ auth_key: Optional[str]
596
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
597
+ timeout: int
598
+ Timeout for the request (default: 60 seconds)
599
+ max_retries: int
600
+ Maximum number of retries (default: 3)
601
+ backoff_factor: float
602
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
603
+ second try without a delay) (default: 0.1)
604
+ Returns
605
+ -------
606
+ relations: Dict[OntologyPropertyReference, ObjectProperty]
607
+ All relations a dict
608
+
609
+ Raises
610
+ ------
611
+ WacomServiceException
612
+ If the graph service returns an error code
613
+ """
614
+ if auth_key is None:
615
+ auth_key, _ = self.handle_token()
616
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{urllib.parse.quote(uri)}/relations"
617
+ headers: dict = {USER_AGENT_HEADER_FLAG: self.user_agent, AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}"}
618
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
619
+ with requests.Session() as session:
620
+ retries: Retry = Retry(
621
+ total=max_retries, backoff_factor=backoff_factor, status_forcelist=[500, 502, 503, 504]
622
+ )
623
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
624
+ response: Response = session.get(url, headers=headers, timeout=timeout, verify=self.verify_calls)
625
+ if response.ok:
626
+ rel: list = response.json().get(RELATIONS_TAG)
627
+ return ObjectProperty.create_from_list(rel)
628
+ raise handle_error("Retrieving relations failed.", response)
629
+
630
+ def labels(
631
+ self,
632
+ uri: str,
633
+ locale: LocaleCode = EN_US,
634
+ auth_key: Optional[str] = None,
635
+ timeout: int = DEFAULT_TIMEOUT,
636
+ max_retries: int = DEFAULT_MAX_RETRIES,
637
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
638
+ ) -> List[Label]:
639
+ """
640
+ Extract list labels of entity.
641
+
642
+ Parameters
643
+ ----------
644
+ uri: str
645
+ Entity URI of the source
646
+ locale: LocaleCode [default:= EN_US]
647
+ ISO-3166 Country Codes and ISO-639 Language Codes in the format <language_code>_<country>, e.g., en_US.
648
+ auth_key: Optional[str] = None
649
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
650
+ timeout: int
651
+ Timeout for the request (default: 60 seconds)
652
+ max_retries: int
653
+ Maximum number of retries (default: 3)
654
+ backoff_factor: float
655
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
656
+ second try without a delay) (default: 0.1)
657
+
658
+ Returns
659
+ -------
660
+ labels: List[Label]
661
+ List of labels of an entity.
662
+
663
+ Raises
664
+ ------
665
+ WacomServiceException
666
+ If the graph service returns an error code
667
+ """
668
+ if auth_key is None:
669
+ auth_key, _ = self.handle_token()
670
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{uri}/labels"
671
+ headers: dict = {USER_AGENT_HEADER_FLAG: self.user_agent, AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}"}
672
+ with requests.Session() as session:
673
+ retries: Retry = Retry(
674
+ total=max_retries, backoff_factor=backoff_factor, status_forcelist=[500, 502, 503, 504]
675
+ )
676
+ session.mount("https://", HTTPAdapter(max_retries=retries))
677
+ response: Response = session.get(
678
+ url, headers=headers, params={LOCALE_TAG: locale}, timeout=timeout, verify=self.verify_calls
679
+ )
680
+ if response.ok:
681
+ response_dict: dict = response.json()
682
+ if LABELS_TAG in response_dict:
683
+ return [Label.create_from_dict(label) for label in response_dict[LABELS_TAG]]
684
+ return []
685
+ raise handle_error("Retrieving labels failed.", response)
686
+
687
+ def literals(
688
+ self,
689
+ uri: str,
690
+ locale: LocaleCode = EN_US,
691
+ auth_key: Optional[str] = None,
692
+ timeout: int = DEFAULT_TIMEOUT,
693
+ max_retries: int = DEFAULT_MAX_RETRIES,
694
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
695
+ ) -> List[DataProperty]:
696
+ """
697
+ Collect all literals of entity.
698
+
699
+ Parameters
700
+ ----------
701
+ uri: str
702
+ Entity URI of the source
703
+ locale: LocaleCode [default:= EN_US]
704
+ ISO-3166 Country Codes and ISO-639 Language Codes in the format <language_code>_<country>, e.g., en_US.
705
+ auth_key: Optional[str] = None
706
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
707
+ timeout: int
708
+ Timeout for the request (default: 60 seconds)
709
+ max_retries: int
710
+ Maximum number of retries (default: 3)
711
+ backoff_factor: float
712
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
713
+ second try without a delay) (default: 0.1).
714
+
715
+ Returns
716
+ -------
717
+ labels: List[DataProperty]
718
+ List of data properties of an entity.
719
+
720
+ Raises
721
+ ------
722
+ WacomServiceException
723
+ If the graph service returns an error code
724
+ """
725
+ if auth_key is None:
726
+ auth_key, _ = self.handle_token()
727
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{uri}/literals"
728
+ headers: dict = {USER_AGENT_HEADER_FLAG: self.user_agent, AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}"}
729
+ with requests.Session() as session:
730
+ retries: Retry = Retry(
731
+ total=max_retries, backoff_factor=backoff_factor, status_forcelist=[500, 502, 503, 504]
732
+ )
733
+ session.mount("https://", HTTPAdapter(max_retries=retries))
734
+ response: Response = session.get(
735
+ url, headers=headers, params={LOCALE_TAG: locale}, timeout=timeout, verify=self.verify_calls
736
+ )
737
+ if response.ok:
738
+ literals: list = response.json().get(DATA_PROPERTIES_TAG)
739
+ return DataProperty.create_from_list(literals)
740
+ raise handle_error(f"Failed to pull literals for {uri}.", response)
741
+
742
+ def create_relation(
743
+ self,
744
+ source: str,
745
+ relation: OntologyPropertyReference,
746
+ target: str,
747
+ auth_key: Optional[str] = None,
748
+ timeout: int = DEFAULT_TIMEOUT,
749
+ max_retries: int = DEFAULT_MAX_RETRIES,
750
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
751
+ ):
752
+ """
753
+ Creates a relation for an entity to a source entity.
754
+
755
+ Parameters
756
+ ----------
757
+ source: str
758
+ Entity URI of the source
759
+ relation: OntologyPropertyReference
760
+ ObjectProperty property
761
+ target: str
762
+ Entity URI of the target
763
+ auth_key: Optional[str] = None
764
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
765
+ timeout: int
766
+ Timeout for the request (default: 60 seconds)
767
+ max_retries: int
768
+ Maximum number of retries (default: 3)
769
+ backoff_factor: float
770
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
771
+ second try without a delay) (default: 0.1)
772
+
773
+ Raises
774
+ ------
775
+ WacomServiceException
776
+ If the graph service returns an error code
777
+ """
778
+ if auth_key is None:
779
+ auth_key, _ = self.handle_token()
780
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{source}/relation"
781
+ headers: dict = {USER_AGENT_HEADER_FLAG: self.user_agent, AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}"}
782
+ params: dict = {RELATION_TAG: relation.iri, TARGET: target}
783
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
784
+ with requests.Session() as session:
785
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
786
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
787
+ response: Response = session.post(
788
+ url, params=params, headers=headers, timeout=timeout, verify=self.verify_calls
789
+ )
790
+ if not response.ok:
791
+ raise handle_error("Creation of relation failed.", response)
792
+
793
+ def create_relations_bulk(
794
+ self,
795
+ source: str,
796
+ relations: Dict[OntologyPropertyReference, List[str]],
797
+ auth_key: Optional[str] = None,
798
+ timeout: int = DEFAULT_TIMEOUT,
799
+ max_retries: int = DEFAULT_MAX_RETRIES,
800
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
801
+ ):
802
+ """
803
+ Creates all the relations for an entity to a source entity.
804
+
805
+ Parameters
806
+ ----------
807
+ source: str
808
+ Entity URI of the source
809
+ relations: Dict[OntologyPropertyReference, List[str]]
810
+ ObjectProperty property and targets mapping.
811
+ auth_key: Optional[str] = None
812
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
813
+ timeout: int
814
+ Timeout for the request (default: 60 seconds)
815
+ max_retries: int
816
+ Maximum number of retries (default: 3)
817
+ backoff_factor: float
818
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
819
+ second try without a delay) (default: 0.1)
820
+
821
+ Raises
822
+ ------
823
+ WacomServiceException
824
+ If the graph service returns an error code
825
+ """
826
+ if auth_key is None:
827
+ auth_key, _ = self.handle_token()
828
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{source}/relations"
829
+ headers: dict = {USER_AGENT_HEADER_FLAG: self.user_agent, AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}"}
830
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
831
+ with requests.Session() as session:
832
+ retries: Retry = Retry(
833
+ total=max_retries, backoff_factor=backoff_factor, status_forcelist=[500, 502, 503, 504]
834
+ )
835
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
836
+ for updates in split_updates(relations):
837
+ response: Response = session.post(
838
+ url, timeout=timeout, json=updates, headers=headers, verify=self.verify_calls
839
+ )
840
+ if not response.ok:
841
+ raise handle_error("Creation of relation failed.", response, payload=updates)
842
+
843
+ def remove_relation(
844
+ self,
845
+ source: str,
846
+ relation: OntologyPropertyReference,
847
+ target: str,
848
+ auth_key: Optional[str] = None,
849
+ timeout: int = DEFAULT_TIMEOUT,
850
+ max_retries: int = DEFAULT_MAX_RETRIES,
851
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
852
+ ):
853
+ """
854
+ Removes a relation.
855
+
856
+ Parameters
857
+ ----------
858
+ source: str
859
+ Entity uri of the source
860
+ relation: OntologyPropertyReference
861
+ ObjectProperty property
862
+ target: str
863
+ Entity uri of the target
864
+ auth_key: Optional[str] = None
865
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
866
+ timeout: int
867
+ Timeout for the request (default: 60 seconds)
868
+ max_retries: int
869
+ Maximum number of retries (default: 3)
870
+ backoff_factor: float
871
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
872
+ second try without a delay) (default: 0.1)
873
+
874
+ Raises
875
+ ------
876
+ WacomServiceException
877
+ If the graph service returns an error code
878
+ """
879
+ if auth_key is None:
880
+ auth_key, _ = self.handle_token()
881
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ENTITY_ENDPOINT}/{source}/relation"
882
+ params: Dict[str, str] = {RELATION_TAG: relation.iri, TARGET: target}
883
+ headers: Dict[str, str] = {
884
+ USER_AGENT_HEADER_FLAG: self.user_agent,
885
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
886
+ }
887
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
888
+ with requests.Session() as session:
889
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
890
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
891
+ # Get response
892
+ response: Response = session.delete(
893
+ url, params=params, headers=headers, timeout=timeout, verify=self.verify_calls
894
+ )
895
+ if not response.ok:
896
+ raise handle_error("Removal of relation failed.", response)
897
+
898
+ def activations(
899
+ self,
900
+ uris: List[str],
901
+ depth: int,
902
+ auth_key: Optional[str] = None,
903
+ timeout: int = DEFAULT_TIMEOUT,
904
+ max_retries: int = DEFAULT_MAX_RETRIES,
905
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
906
+ ) -> Tuple[Dict[str, ThingObject], List[Tuple[str, OntologyPropertyReference, str]]]:
907
+ """
908
+ Spreading activation, retrieving the entities related to an entity.
909
+
910
+ Parameters
911
+ ----------
912
+ uris: List[str]
913
+ List of URIS for entity.
914
+ depth: int
915
+ Depth of activations
916
+ auth_key: Optional[str] = None
917
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
918
+ timeout: int
919
+ Timeout for the request (default: 60 seconds)
920
+ max_retries: int
921
+ Maximum number of retries (default: 3)
922
+ backoff_factor: float
923
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
924
+ second try without a delay) (default: 0.1)
925
+
926
+ Returns
927
+ -------
928
+ entity_map: Dict[str, ThingObject]
929
+ Map with entity and its URI as key.
930
+ relations: List[Tuple[str, OntologyPropertyReference, str]]
931
+ List of relations with subject predicate, (Property), and subject
932
+
933
+ Raises
934
+ ------
935
+ WacomServiceException
936
+ If the graph service returns an error code, and activation failed.
937
+ """
938
+ if auth_key is None:
939
+ auth_key, _ = self.handle_token()
940
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.ACTIVATIONS_ENDPOINT}"
941
+
942
+ headers: Dict[str, str] = {
943
+ USER_AGENT_HEADER_FLAG: self.user_agent,
944
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
945
+ }
946
+ params: dict = {URIS_TAG: uris, ACTIVATION_TAG: depth}
947
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
948
+ with requests.Session() as session:
949
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
950
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
951
+ response: Response = session.get(
952
+ url, headers=headers, params=params, timeout=timeout, verify=self.verify_calls
953
+ )
954
+ if response.ok:
955
+ entities: Dict[str, Any] = response.json()
956
+ things: Dict[str, ThingObject] = {e[URI_TAG]: ThingObject.from_dict(e) for e in entities[ENTITIES_TAG]}
957
+ relations: List[Tuple[str, OntologyPropertyReference, str]] = []
958
+ for r in entities[RELATIONS_TAG]:
959
+ relation: OntologyPropertyReference = OntologyPropertyReference.parse(r[PREDICATE])
960
+ relations.append((r[SUBJECT], relation, r[OBJECT]))
961
+ if r[SUBJECT] in things:
962
+ things[r[SUBJECT]].add_relation(ObjectProperty(relation, outgoing=[r[OBJECT]]))
963
+ return things, relations
964
+ raise handle_error(f"Activation failed. uris:= {uris} activation:={depth}).", response)
965
+
966
+ def listing(
967
+ self,
968
+ filter_type: OntologyClassReference,
969
+ page_id: Optional[str] = None,
970
+ limit: int = 30,
971
+ locale: Optional[LocaleCode] = None,
972
+ visibility: Optional[Visibility] = None,
973
+ is_owner: Optional[bool] = None,
974
+ estimate_count: bool = False,
975
+ auth_key: Optional[str] = None,
976
+ timeout: int = DEFAULT_TIMEOUT,
977
+ max_retries: int = DEFAULT_MAX_RETRIES,
978
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
979
+ ) -> Tuple[List[ThingObject], int, str]:
980
+ """
981
+ List all entities visible to users.
982
+
983
+ Parameters
984
+ ----------
985
+ filter_type: OntologyClassReference
986
+ Filtering with entity
987
+ page_id: Optional[str]
988
+ Page id. Start from this page id
989
+ limit: int
990
+ Limit of the returned entities.
991
+ locale: Optional[LanguageCode] [default:=None]
992
+ ISO-3166 Country Codes and ISO-639 Language Codes in the format '<language_code>_<country>', e.g., en_US.
993
+ visibility: Optional[Visibility] [default:=None]
994
+ Filter the entities based on its visibilities
995
+ is_owner: Optional[bool] [default:=None]
996
+ Filter the entities based on its owner
997
+ estimate_count: bool [default:=False]
998
+ Request an estimate of the entities in a tenant.
999
+ auth_key: Optional[str] = None
1000
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1001
+ timeout: int
1002
+ Timeout for the request (default: 60 seconds)
1003
+ max_retries: int
1004
+ Maximum number of retries
1005
+ backoff_factor: float
1006
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1007
+ second try without a delay)
1008
+
1009
+ Returns
1010
+ -------
1011
+ entities: List[ThingObject]
1012
+ List of entities
1013
+ estimated_total_number: int
1014
+ Number of all entities
1015
+ next_page_id: str
1016
+ Identifier of the next page
1017
+
1018
+ Raises
1019
+ ------
1020
+ WacomServiceException
1021
+ If the graph service returns an error code
1022
+ """
1023
+ if auth_key is None:
1024
+ auth_key, _ = self.handle_token()
1025
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.LISTING_ENDPOINT}"
1026
+ # Header with auth token
1027
+ headers: Dict[str, str] = {
1028
+ USER_AGENT_HEADER_FLAG: self.user_agent,
1029
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
1030
+ }
1031
+ # Parameter with filtering and limit
1032
+ parameters: Dict[str, str] = {TYPE_TAG: filter_type.iri, LIMIT_PARAMETER: limit, ESTIMATE_COUNT: estimate_count}
1033
+ if locale:
1034
+ parameters[LOCALE_TAG] = locale
1035
+ if visibility:
1036
+ parameters[VISIBILITY_TAG] = str(visibility.value)
1037
+ if is_owner is not None:
1038
+ parameters[IS_OWNER_PARAM] = str(is_owner)
1039
+ # If filtering is configured
1040
+ if page_id is not None:
1041
+ parameters[NEXT_PAGE_ID_TAG] = page_id
1042
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1043
+ with requests.Session() as session:
1044
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1045
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1046
+ # Send request
1047
+ response: Response = session.get(
1048
+ url, params=parameters, headers=headers, timeout=timeout, verify=self.verify_calls
1049
+ )
1050
+ # If response is successful
1051
+ if response.ok:
1052
+ entities_resp: dict = response.json()
1053
+ next_page_id: str = entities_resp[NEXT_PAGE_ID_TAG]
1054
+ estimated_total_number: int = entities_resp.get(TOTAL_COUNT, 0)
1055
+ entities: List[ThingObject] = []
1056
+ if LISTING in entities_resp:
1057
+ for e in entities_resp[LISTING]:
1058
+ thing: ThingObject = ThingObject.from_dict(e)
1059
+ thing.status_flag = EntityStatus.SYNCED
1060
+ entities.append(thing)
1061
+ return entities, estimated_total_number, next_page_id
1062
+ raise handle_error(f"Failed to list the entities (since:= {page_id}, limit:={limit}).", response)
1063
+
1064
+ def search_all(
1065
+ self,
1066
+ search_term: str,
1067
+ language_code: LocaleCode,
1068
+ types: List[OntologyClassReference],
1069
+ limit: int = 30,
1070
+ next_page_id: str = None,
1071
+ auth_key: Optional[str] = None,
1072
+ timeout: int = DEFAULT_TIMEOUT,
1073
+ max_retries: int = DEFAULT_MAX_RETRIES,
1074
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1075
+ ) -> Tuple[List[ThingObject], str]:
1076
+ """Search term in labels, literals and description.
1077
+
1078
+ Parameters
1079
+ ----------
1080
+ auth_key: str
1081
+ Auth key from user
1082
+ search_term: str
1083
+ Search term.
1084
+ language_code: LocaleCode
1085
+ ISO-3166 Country Codes and ISO-639 Language Codes in the format '<language_code>_<country>', e.g., en_US.
1086
+ types: List[OntologyClassReference]
1087
+ Limits the types for search.
1088
+ limit: int (default:= 30)
1089
+ Size of the page for pagination.
1090
+ next_page_id: str (default:=None)
1091
+ ID of the next page within pagination.
1092
+ timeout: int
1093
+ Timeout for the request (default: 60 seconds)
1094
+ max_retries: int
1095
+ Maximum number of retries
1096
+ backoff_factor: float
1097
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1098
+ second try without a delay)
1099
+
1100
+ Returns
1101
+ -------
1102
+ results: List[ThingObject]
1103
+ List of things matching the search term
1104
+ next_page_id: str
1105
+ ID of the next page.
1106
+
1107
+ Raises
1108
+ ------
1109
+ WacomServiceException
1110
+ If the graph service returns an error code.
1111
+ """
1112
+ if auth_key is None:
1113
+ auth_key, _ = self.handle_token()
1114
+ headers: Dict[str, str] = {
1115
+ USER_AGENT_HEADER_FLAG: self.user_agent,
1116
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
1117
+ }
1118
+ parameters: Dict[str, Any] = {
1119
+ SEARCH_TERM: search_term,
1120
+ LANGUAGE_PARAMETER: language_code,
1121
+ TYPES_PARAMETER: [ot.iri for ot in types],
1122
+ LIMIT: limit,
1123
+ NEXT_PAGE_ID_TAG: next_page_id,
1124
+ }
1125
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.SEARCH_TYPES_ENDPOINT}"
1126
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1127
+ with requests.Session() as session:
1128
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1129
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1130
+ response: Response = session.get(
1131
+ url, headers=headers, params=parameters, timeout=timeout, verify=self.verify_calls
1132
+ )
1133
+ if response.ok:
1134
+ return WacomKnowledgeService.__search_results__(response.json())
1135
+ raise handle_error(f"Search on labels {search_term} failed. ", response)
1136
+
1137
+ def search_labels(
1138
+ self,
1139
+ search_term: str,
1140
+ language_code: LocaleCode,
1141
+ limit: int = 30,
1142
+ next_page_id: str = None,
1143
+ auth_key: Optional[str] = None,
1144
+ timeout: int = DEFAULT_TIMEOUT,
1145
+ max_retries: int = DEFAULT_MAX_RETRIES,
1146
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1147
+ ) -> Tuple[List[ThingObject], str]:
1148
+ """Search for matches in labels.
1149
+
1150
+ Parameters
1151
+ ----------
1152
+ search_term: str
1153
+ Search term.
1154
+ language_code: LocaleCode
1155
+ ISO-3166 Country Codes and ISO-639 Language Codes in the format '<language_code>_<country>', e.g., en_US.
1156
+ limit: int (default:= 30)
1157
+ Size of the page for pagination.
1158
+ next_page_id: str (default:=None)
1159
+ ID of the next page within pagination.
1160
+ auth_key: Optional[str] = None
1161
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1162
+ timeout: int
1163
+ Timeout for the request (default: 60 seconds)
1164
+ max_retries: int
1165
+ Maximum number of retries
1166
+ backoff_factor: float
1167
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1168
+ second try without a delay)
1169
+
1170
+ Returns
1171
+ -------
1172
+ results: List[ThingObject]
1173
+ List of things matching the search term
1174
+ next_page_id: str
1175
+ ID of the next page.
1176
+
1177
+ Raises
1178
+ ------
1179
+ WacomServiceException
1180
+ If the graph service returns an error code.
1181
+ """
1182
+ if auth_key is None:
1183
+ auth_key, _ = self.handle_token()
1184
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.SEARCH_LABELS_ENDPOINT}"
1185
+ headers: Dict[str, str] = {
1186
+ USER_AGENT_HEADER_FLAG: self.user_agent,
1187
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
1188
+ }
1189
+ parameters: Dict[str, Any] = {
1190
+ SEARCH_TERM: search_term,
1191
+ LOCALE_TAG: language_code,
1192
+ LIMIT: limit,
1193
+ NEXT_PAGE_ID_TAG: next_page_id,
1194
+ }
1195
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1196
+ with requests.Session() as session:
1197
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1198
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1199
+ response: Response = session.get(
1200
+ url, headers=headers, params=parameters, timeout=timeout, verify=self.verify_calls
1201
+ )
1202
+ if response.ok:
1203
+ return WacomKnowledgeService.__search_results__(response.json())
1204
+ raise handle_error(f"Search on labels {search_term} failed. ", response)
1205
+
1206
+ def search_literal(
1207
+ self,
1208
+ search_term: str,
1209
+ literal: OntologyPropertyReference,
1210
+ pattern: SearchPattern = SearchPattern.REGEX,
1211
+ language_code: LocaleCode = EN_US,
1212
+ limit: int = 30,
1213
+ next_page_id: str = None,
1214
+ auth_key: Optional[str] = None,
1215
+ timeout: int = DEFAULT_TIMEOUT,
1216
+ max_retries: int = DEFAULT_MAX_RETRIES,
1217
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1218
+ ) -> Tuple[List[ThingObject], str]:
1219
+ """
1220
+ Search for matches in literals.
1221
+
1222
+ Parameters
1223
+ ----------
1224
+ search_term: str
1225
+ Search term.
1226
+ literal: OntologyPropertyReference
1227
+ Literal used for the search
1228
+ pattern: SearchPattern (default:= SearchPattern.REGEX)
1229
+ Search pattern. The chosen search pattern must fit the type of the entity.
1230
+ language_code: LocaleCode (default:= EN_US)
1231
+ ISO-3166 Country Codes and ISO-639 Language Codes in the format '<language_code>_<country>', e.g., en_US.
1232
+ limit: int (default:= 30)
1233
+ Size of the page for pagination.
1234
+ next_page_id: str (default:=None)
1235
+ ID of the next page within pagination.
1236
+ auth_key: Optional[str] = None
1237
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1238
+ timeout: int
1239
+ Timeout for the request (default: 60 seconds)
1240
+ max_retries: int
1241
+ Maximum number of retries
1242
+ backoff_factor: float
1243
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1244
+ second try without a delay)
1245
+
1246
+ Returns
1247
+ -------
1248
+ results: List[ThingObject]
1249
+ List of things matching the search term
1250
+ next_page_id: str
1251
+ ID of the next page.
1252
+
1253
+ Raises
1254
+ ------
1255
+ WacomServiceException
1256
+ If the graph service returns an error code.
1257
+ """
1258
+ if auth_key is None:
1259
+ auth_key, _ = self.handle_token()
1260
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.SEARCH_LITERALS_ENDPOINT}"
1261
+ parameters: Dict[str, Any] = {
1262
+ VALUE: search_term,
1263
+ LITERAL_PARAMETER: literal.iri,
1264
+ LANGUAGE_PARAMETER: language_code,
1265
+ LIMIT_PARAMETER: limit,
1266
+ SEARCH_PATTERN_PARAMETER: pattern.value,
1267
+ NEXT_PAGE_ID_TAG: next_page_id,
1268
+ }
1269
+ headers: Dict[str, str] = {
1270
+ USER_AGENT_HEADER_FLAG: self.user_agent,
1271
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
1272
+ }
1273
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1274
+ with requests.Session() as session:
1275
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1276
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1277
+ response: Response = session.get(
1278
+ url, headers=headers, params=parameters, timeout=timeout, verify=self.verify_calls
1279
+ )
1280
+ if response.ok:
1281
+ return WacomKnowledgeService.__search_results__(response.json())
1282
+ raise handle_error(f"Search on literals {search_term} failed. ", response)
1283
+
1284
+ def search_relation(
1285
+ self,
1286
+ relation: OntologyPropertyReference,
1287
+ language_code: LocaleCode,
1288
+ subject_uri: str = None,
1289
+ object_uri: str = None,
1290
+ limit: int = 30,
1291
+ next_page_id: str = None,
1292
+ auth_key: Optional[str] = None,
1293
+ timeout: int = DEFAULT_TIMEOUT,
1294
+ max_retries: int = DEFAULT_MAX_RETRIES,
1295
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1296
+ ) -> Tuple[List[ThingObject], str]:
1297
+ """
1298
+ Search for matches in literals.
1299
+
1300
+ Parameters
1301
+ ----------
1302
+ relation: OntologyPropertyReference
1303
+ Search term.
1304
+ language_code: LocaleCode
1305
+ ISO-3166 Country Codes and ISO-639 Language Codes in the format '<language_code>_<country>', e.g., en_US.
1306
+ subject_uri: str (default:=None)
1307
+ URI of the subject
1308
+ object_uri: str (default:=None)
1309
+ URI of the object
1310
+ limit: int (default:= 30)
1311
+ Size of the page for pagination.
1312
+ next_page_id: str (default:=None)
1313
+ ID of the next page within pagination.
1314
+ auth_key: Optional[str] = None
1315
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1316
+ timeout: int
1317
+ Timeout for the request (default: 60 seconds)
1318
+ max_retries: int
1319
+ Maximum number of retries
1320
+ backoff_factor: float
1321
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1322
+ second try without a delay)
1323
+
1324
+ Returns
1325
+ -------
1326
+ results: List[ThingObject]
1327
+ List of things matching the search term
1328
+ next_page_id: str
1329
+ ID of the next page.
1330
+
1331
+ Raises
1332
+ ------
1333
+ WacomServiceException
1334
+ If the graph service returns an error code.
1335
+ """
1336
+ if auth_key is None:
1337
+ auth_key, _ = self.handle_token()
1338
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.SEARCH_RELATION_ENDPOINT}"
1339
+ parameters: Dict[str, Any] = {
1340
+ SUBJECT_URI: subject_uri,
1341
+ RELATION_URI: relation.iri,
1342
+ OBJECT_URI: object_uri,
1343
+ LANGUAGE_PARAMETER: language_code,
1344
+ LIMIT: limit,
1345
+ NEXT_PAGE_ID_TAG: next_page_id,
1346
+ }
1347
+ headers: Dict[str, str] = {
1348
+ USER_AGENT_HEADER_FLAG: self.user_agent,
1349
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
1350
+ }
1351
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1352
+ with requests.Session() as session:
1353
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1354
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1355
+ response: Response = session.get(
1356
+ url, headers=headers, params=parameters, timeout=timeout, verify=self.verify_calls
1357
+ )
1358
+ if response.ok:
1359
+ return WacomKnowledgeService.__search_results__(response.json())
1360
+ raise handle_error(
1361
+ f"Search on: subject:={subject_uri}, relation {relation.iri}, " f"object:= {object_uri} failed. ",
1362
+ response,
1363
+ )
1364
+
1365
+ def search_description(
1366
+ self,
1367
+ search_term: str,
1368
+ language_code: LocaleCode,
1369
+ limit: int = 30,
1370
+ next_page_id: str = None,
1371
+ auth_key: Optional[str] = None,
1372
+ timeout: int = DEFAULT_TIMEOUT,
1373
+ max_retries: int = DEFAULT_MAX_RETRIES,
1374
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1375
+ ) -> Tuple[List[ThingObject], str]:
1376
+ """Search for matches in description.
1377
+
1378
+ Parameters
1379
+ ----------
1380
+ search_term: str
1381
+ Search term.
1382
+ language_code: LocaleCode
1383
+ ISO-3166 Country Codes and ISO-639 Language Codes in the format '<language_code>_<country>', e.g., en_US.
1384
+ limit: int (default:= 30)
1385
+ Size of the page for pagination.
1386
+ next_page_id: str (default:=None)
1387
+ ID of the next page within pagination.
1388
+ auth_key: Optional[str] = None
1389
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1390
+ timeout: int
1391
+ Timeout for the request (default: 60 seconds)
1392
+ max_retries: int
1393
+ Maximum number of retries
1394
+ backoff_factor: float
1395
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1396
+ second try without a delay)
1397
+
1398
+ Returns
1399
+ -------
1400
+ results: List[ThingObject]
1401
+ List of things matching the search term
1402
+ next_page_id: str
1403
+ ID of the next page.
1404
+
1405
+ Raises
1406
+ ------
1407
+ WacomServiceException
1408
+ If the graph service returns an error code.
1409
+ """
1410
+ if auth_key is None:
1411
+ auth_key, _ = self.handle_token()
1412
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.SEARCH_DESCRIPTION_ENDPOINT}"
1413
+ parameters: Dict[str, Any] = {
1414
+ SEARCH_TERM: search_term,
1415
+ LOCALE_TAG: language_code,
1416
+ LIMIT: limit,
1417
+ NEXT_PAGE_ID_TAG: next_page_id,
1418
+ }
1419
+ headers: dict = {AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}", USER_AGENT_HEADER_FLAG: self.user_agent}
1420
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1421
+ with requests.Session() as session:
1422
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1423
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1424
+ response: Response = session.get(
1425
+ url, headers=headers, params=parameters, timeout=timeout, verify=self.verify_calls
1426
+ )
1427
+ if response.ok:
1428
+ return WacomKnowledgeService.__search_results__(response.json())
1429
+ raise handle_error(f"Search on labels {search_term}@{language_code} failed. ", response)
1430
+
1431
+ @staticmethod
1432
+ def __search_results__(response: Dict[str, Any]) -> Tuple[List[ThingObject], str]:
1433
+ """
1434
+ Convert response to list of ThingObjects and next page id.
1435
+
1436
+ Parameters
1437
+ ----------
1438
+ response: Dict[str, Any]
1439
+ Response from the service.
1440
+
1441
+ Returns
1442
+ -------
1443
+ results: List[ThingObject]
1444
+ List of things matching the search term
1445
+ next_page_id: str
1446
+ ID of the next page.
1447
+ """
1448
+ results: List[ThingObject] = []
1449
+ for elem in response["result"]:
1450
+ results.append(ThingObject.from_dict(elem))
1451
+ return results, response[NEXT_PAGE_ID_TAG]
1452
+
1453
+ def set_entity_image_local(
1454
+ self,
1455
+ entity_uri: str,
1456
+ path: Path,
1457
+ auth_key: Optional[str] = None,
1458
+ timeout: int = DEFAULT_TIMEOUT,
1459
+ max_retries: int = DEFAULT_MAX_RETRIES,
1460
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1461
+ ) -> str:
1462
+ """Setting the image of the entity.
1463
+ The image is stored locally.
1464
+
1465
+ Parameters
1466
+ ----------
1467
+ entity_uri: str
1468
+ URI of the entity.
1469
+ path: Path
1470
+ The path of image.
1471
+ auth_key: Optional[str] = None
1472
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1473
+ timeout: int
1474
+ Timeout for the request (default: 60 seconds)
1475
+ max_retries: int
1476
+ Maximum number of retries
1477
+ backoff_factor: float
1478
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1479
+ second try without a delay)
1480
+
1481
+ Returns
1482
+ -------
1483
+ image_id: str
1484
+ ID of uploaded image
1485
+
1486
+ Raises
1487
+ ------
1488
+ WacomServiceException
1489
+ If the graph service returns an error code.
1490
+ """
1491
+ with path.open("rb") as fp:
1492
+ image_bytes: bytes = fp.read()
1493
+ file_name: str = str(path.absolute())
1494
+ _, file_extension = os.path.splitext(file_name.lower())
1495
+ mime_type = MIME_TYPE[file_extension]
1496
+ return self.set_entity_image(
1497
+ entity_uri,
1498
+ image_bytes,
1499
+ file_name,
1500
+ mime_type,
1501
+ auth_key=auth_key,
1502
+ timeout=timeout,
1503
+ max_retries=max_retries,
1504
+ backoff_factor=backoff_factor,
1505
+ )
1506
+
1507
+ def set_entity_image_url(
1508
+ self,
1509
+ entity_uri: str,
1510
+ image_url: str,
1511
+ file_name: Optional[str] = None,
1512
+ mime_type: Optional[str] = None,
1513
+ auth_key: Optional[str] = None,
1514
+ timeout: int = DEFAULT_TIMEOUT,
1515
+ max_retries: int = DEFAULT_MAX_RETRIES,
1516
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1517
+ ) -> str:
1518
+ """Setting the image of the entity.
1519
+ The image for the URL is downloaded and then pushed to the backend.
1520
+
1521
+ Parameters
1522
+ ----------
1523
+ auth_key: str
1524
+ Auth key from user
1525
+ entity_uri: str
1526
+ URI of the entity.
1527
+ image_url: str
1528
+ URL of the image.
1529
+ file_name: str (default:=None)
1530
+ Name of the file. If None the name is extracted from URL.
1531
+ mime_type: str (default:=None)
1532
+ Mime type.
1533
+ auth_key: Optional[str] = None
1534
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1535
+ timeout: int
1536
+ Timeout for the request (default: 60 seconds)
1537
+ max_retries: int
1538
+ Maximum number of retries
1539
+ backoff_factor: float
1540
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1541
+ second try without a delay)
1542
+ Returns
1543
+ -------
1544
+ image_id: str
1545
+ ID of uploaded image
1546
+
1547
+ Raises
1548
+ ------
1549
+ WacomServiceException
1550
+ If the graph service returns an error code.
1551
+ """
1552
+ mount_point: str = "https://" if image_url.startswith("https") else "http://"
1553
+ with requests.Session() as session:
1554
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1555
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1556
+ headers: Dict[str, str] = {USER_AGENT_HEADER_FLAG: self.user_agent}
1557
+ response: Response = session.get(image_url, headers=headers, timeout=timeout, verify=self.verify_calls)
1558
+ if response.ok:
1559
+ image_bytes: bytes = response.content
1560
+ file_name: str = image_url if file_name is None else file_name
1561
+ if mime_type is None:
1562
+ _, file_extension = os.path.splitext(file_name.lower())
1563
+ if file_extension not in MIME_TYPE:
1564
+ raise handle_error(
1565
+ "Creation of entity image failed. Mime-type cannot be identified or is not " "supported.",
1566
+ response,
1567
+ )
1568
+ mime_type = MIME_TYPE[file_extension]
1569
+
1570
+ return self.set_entity_image(
1571
+ entity_uri,
1572
+ image_bytes,
1573
+ file_name,
1574
+ mime_type,
1575
+ auth_key=auth_key,
1576
+ timeout=timeout,
1577
+ max_retries=max_retries,
1578
+ backoff_factor=backoff_factor,
1579
+ )
1580
+ raise handle_error("Creation of entity image failed.", response)
1581
+
1582
+ def set_entity_image(
1583
+ self,
1584
+ entity_uri: str,
1585
+ image_byte: bytes,
1586
+ file_name: str = "icon.jpg",
1587
+ mime_type: str = "image/jpeg",
1588
+ auth_key: Optional[str] = None,
1589
+ timeout: int = DEFAULT_TIMEOUT,
1590
+ max_retries: int = DEFAULT_MAX_RETRIES,
1591
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1592
+ ) -> str:
1593
+ """Setting the image of the entity.
1594
+ The image for the URL is downloaded and then pushed to the backend.
1595
+
1596
+ Parameters
1597
+ ----------
1598
+ entity_uri: str
1599
+ URI of the entity.
1600
+ image_byte: bytes
1601
+ Binary encoded image.
1602
+ file_name: str (default:=None)
1603
+ Name of the file. If None the name is extracted from URL.
1604
+ mime_type: str (default:=None)
1605
+ Mime type.
1606
+ auth_key: Optional[str] = None
1607
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1608
+ timeout: int
1609
+ Timeout for the request (default: 60 seconds)
1610
+ max_retries: int
1611
+ Maximum number of retries
1612
+ backoff_factor: float
1613
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1614
+ second try without a delay)
1615
+
1616
+ Returns
1617
+ -------
1618
+ image_id: str
1619
+ ID of uploaded image
1620
+
1621
+ Raises
1622
+ ------
1623
+ WacomServiceException
1624
+ If the graph service returns an error code.
1625
+ """
1626
+ if auth_key is None:
1627
+ auth_key, _ = self.handle_token()
1628
+ headers: dict = {AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}", USER_AGENT_HEADER_FLAG: self.user_agent}
1629
+ files: List[Tuple[str, Tuple[str, bytes, str]]] = [("file", (file_name, image_byte, mime_type))]
1630
+ url: str = f"{self.service_base_url}{self.ENTITY_IMAGE_ENDPOINT}{urllib.parse.quote(entity_uri)}"
1631
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1632
+ with requests.Session() as session:
1633
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1634
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1635
+ response: Response = session.patch(
1636
+ url, headers=headers, files=files, timeout=timeout, verify=self.verify_calls
1637
+ )
1638
+ if response.ok:
1639
+ return response.json()["imageId"]
1640
+ raise handle_error("Creation of entity image failed.", response)
1641
+
1642
+ def import_entities(
1643
+ self,
1644
+ entities: List[ThingObject],
1645
+ auth_key: Optional[str] = None,
1646
+ timeout: int = DEFAULT_TIMEOUT,
1647
+ max_retries: int = DEFAULT_MAX_RETRIES,
1648
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1649
+ ) -> str:
1650
+ """Import entities to the graph.
1651
+
1652
+ Parameters
1653
+ ----------
1654
+ entities: List[ThingObject]
1655
+ List of entities to import.
1656
+ auth_key: Optional[str] = None
1657
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1658
+ timeout: int
1659
+ Timeout for the request (default: 60 seconds)
1660
+ max_retries: int
1661
+ Maximum number of retries
1662
+ backoff_factor: float
1663
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1664
+ second try without a delay)
1665
+
1666
+ Returns
1667
+ -------
1668
+ job_id: str
1669
+ ID of the job
1670
+
1671
+ Raises
1672
+ ------
1673
+ WacomServiceException
1674
+ If the graph service returns an error code.
1675
+ """
1676
+ if auth_key is None:
1677
+ auth_key, _ = self.handle_token()
1678
+ headers: dict = {USER_AGENT_HEADER_FLAG: self.user_agent, AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}"}
1679
+ ndjson_lines: List[str] = []
1680
+ for obj in entities:
1681
+ data_dict = obj.__import_format_dict__()
1682
+ ndjson_lines.append(json.dumps(data_dict)) # Convert each dict to a JSON string
1683
+
1684
+ ndjson_content = "\n".join(ndjson_lines) # Join JSON strings with newline
1685
+
1686
+ # Compress the NDJSON string to a gzip byte array
1687
+ compressed_data: bytes = gzip.compress(ndjson_content.encode("utf-8"))
1688
+ with open("import.gzip", "wb") as f:
1689
+ f.write(compressed_data)
1690
+ files: List[Tuple[str, Tuple[str, bytes, str]]] = [
1691
+ ("file", ("import.njson", compressed_data, "application/x-gzip"))
1692
+ ]
1693
+ url: str = f"{self.service_base_url}{self.IMPORT_ENTITIES_ENDPOINT}"
1694
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1695
+ with requests.Session() as session:
1696
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1697
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1698
+ response: Response = session.post(
1699
+ url, headers=headers, files=files, timeout=timeout, verify=self.verify_calls
1700
+ )
1701
+ if response.ok:
1702
+ return response.json()["jobId"]
1703
+ raise handle_error("Import endpoint returns an error.", response)
1704
+
1705
+ def job_status(
1706
+ self,
1707
+ job_id: str,
1708
+ auth_key: Optional[str] = None,
1709
+ timeout: int = DEFAULT_TIMEOUT,
1710
+ max_retries: int = DEFAULT_MAX_RETRIES,
1711
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1712
+ ) -> Dict[str, Any]:
1713
+ """
1714
+ Retrieve the status of the job.
1715
+
1716
+ Parameters
1717
+ ----------
1718
+ job_id: str
1719
+ ID of the job
1720
+ auth_key: Optional[str] = None
1721
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1722
+ timeout: int
1723
+ Timeout for the request (default: 60 seconds)
1724
+ max_retries: int
1725
+ Maximum number of retries
1726
+ backoff_factor: float
1727
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1728
+ second try without a delay)
1729
+
1730
+ Returns
1731
+ -------
1732
+ job_status: Dict[str, Any]
1733
+ Status of the job
1734
+ """
1735
+ if auth_key is None:
1736
+ auth_key, _ = self.handle_token()
1737
+ headers: dict = {USER_AGENT_HEADER_FLAG: self.user_agent, AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}"}
1738
+ url: str = f"{self.service_base_url}{self.IMPORT_ENTITIES_ENDPOINT}/{job_id}"
1739
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1740
+ with requests.Session() as session:
1741
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1742
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1743
+ response: Response = session.get(url, headers=headers, timeout=timeout, verify=self.verify_calls)
1744
+ if response.ok:
1745
+ return response.json()
1746
+ raise handle_error(f"Retrieving job status for {job_id} failed.", response)
1747
+
1748
+ # ------------------------------------ Admin endpoints -------------------------------------------------------------
1749
+
1750
+ def rebuild_vector_search_index(
1751
+ self,
1752
+ prune: bool = False,
1753
+ auth_key: Optional[str] = None,
1754
+ timeout: int = DEFAULT_TIMEOUT,
1755
+ max_retries: int = DEFAULT_MAX_RETRIES,
1756
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1757
+ ):
1758
+ """
1759
+ Rebuild the vector search index.
1760
+
1761
+ **Remark:**
1762
+ Works for users with role 'TenantAdmin'.
1763
+
1764
+ Parameters
1765
+ ----------
1766
+ prune: bool
1767
+ Prune the index before rebuilding.
1768
+ auth_key: Optional[str] = None
1769
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1770
+ timeout: int
1771
+ Timeout for the request (default: 60 seconds)
1772
+ max_retries: int
1773
+ Maximum number of retries (default: 3)
1774
+ backoff_factor: float
1775
+ A backoff factor to apply between attempts after the second try (most errors are resolved immediately by a
1776
+ second try without a delay)
1777
+ """
1778
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.REBUILD_VECTOR_SEARCH_INDEX}"
1779
+ params: Dict[str, str] = {PRUNE_PARAM: prune}
1780
+ if UserRole.ADMIN.value not in self.current_session.roles:
1781
+ raise WacomServiceException('Only users with role "Admin" can rebuild the vector search index.')
1782
+ if auth_key is None:
1783
+ auth_key, _ = self.handle_token()
1784
+ headers: Dict[str, str] = {
1785
+ USER_AGENT_HEADER_FLAG: self.user_agent,
1786
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
1787
+ }
1788
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1789
+ with requests.Session() as session:
1790
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1791
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1792
+ response: Response = session.post(
1793
+ url, params=params, headers=headers, timeout=timeout, verify=self.verify_calls
1794
+ )
1795
+ if not response.ok:
1796
+ raise handle_error("Rebuilding vector search index failed.", response)
1797
+
1798
+ def rebuild_nel_index(
1799
+ self,
1800
+ nel_index: Literal["western", "japanese"],
1801
+ prune: bool = False,
1802
+ auth_key: Optional[str] = None,
1803
+ timeout: int = DEFAULT_TIMEOUT,
1804
+ max_retries: int = DEFAULT_MAX_RETRIES,
1805
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1806
+ ):
1807
+ """
1808
+ Rebuild the named entity linking index.
1809
+
1810
+ **Remark:**
1811
+ Works for users with role 'TenantAdmin'
1812
+
1813
+ Parameters
1814
+ ----------
1815
+ nel_index: Literal['western', 'japanese']
1816
+ Named entity linking index to rebuild.
1817
+ prune: bool
1818
+ Prune the index before rebuilding.
1819
+ auth_key: Optional[str] = None
1820
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1821
+ timeout: int
1822
+ Timeout for the request (default: 60 seconds)
1823
+ max_retries: int
1824
+ Maximum number of retries
1825
+ backoff_factor: float
1826
+ A backoff factor to apply between attempts after.
1827
+
1828
+ Raises
1829
+ ------
1830
+ WacomServiceException
1831
+ If the graph service returns an error code.
1832
+ """
1833
+ url: str = f"{self.service_base_url}{WacomKnowledgeService.REBUILD_NEL_INDEX}"
1834
+ params: Dict[str, str] = {PRUNE_PARAM: prune, NEL_PARAM: nel_index}
1835
+ if auth_key is None:
1836
+ auth_key, _ = self.handle_token()
1837
+ if UserRole.ADMIN.value not in self.current_session.roles:
1838
+ raise WacomServiceException('Only users with role "Admin" can rebuild the vector search index.')
1839
+ auth_key, _ = self.handle_token()
1840
+ headers: Dict[str, str] = {
1841
+ USER_AGENT_HEADER_FLAG: self.user_agent,
1842
+ AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}",
1843
+ }
1844
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1845
+ with requests.Session() as session:
1846
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1847
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1848
+ response: Response = session.post(
1849
+ url, params=params, headers=headers, timeout=timeout, verify=self.verify_calls
1850
+ )
1851
+ if not response.ok:
1852
+ raise handle_error("Rebuilding vector search index failed.", response)
1853
+
1854
+ def ontology_update(
1855
+ self,
1856
+ fix: bool = False,
1857
+ auth_key: Optional[str] = None,
1858
+ timeout: int = DEFAULT_TIMEOUT,
1859
+ max_retries: int = DEFAULT_MAX_RETRIES,
1860
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
1861
+ ):
1862
+ """
1863
+ Update the ontology.
1864
+
1865
+ **Remark:**
1866
+ Works for users with role 'TenantAdmin'.
1867
+
1868
+ Parameters
1869
+ ----------
1870
+ fix: bool [default:=False]
1871
+ Fix the ontology if tenant is in inconsistent state.
1872
+ auth_key: Optional[str] = None
1873
+ If the auth key is set the logged-in user (if any) will be ignored and the auth key will be used.
1874
+ timeout: int
1875
+ Timeout for the request (default: 60 seconds)
1876
+ max_retries: int
1877
+ Maximum number of retries
1878
+ backoff_factor: float
1879
+ A backoff factor to apply between attempts after the second try.
1880
+
1881
+ Raises
1882
+ ------
1883
+ WacomServiceException
1884
+ If the graph service returns an error code and commit failed.
1885
+ """
1886
+ if auth_key is None:
1887
+ auth_key, _ = self.handle_token()
1888
+ url: str = f'{self.service_base_url}{WacomKnowledgeService.ONTOLOGY_UPDATE_ENDPOINT}{"/fix" if fix else ""}'
1889
+ # Header with auth token
1890
+ headers: dict = {USER_AGENT_HEADER_FLAG: self.user_agent, AUTHORIZATION_HEADER_FLAG: f"Bearer {auth_key}"}
1891
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
1892
+ with requests.Session() as session:
1893
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
1894
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
1895
+ response: Response = session.patch(url, headers=headers, timeout=timeout, verify=self.verify_calls)
1896
+ if not response.ok:
1897
+ raise handle_error("Ontology update fails.", response)