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,445 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright © 2021-present Wacom. All rights reserved.
3
+ import enum
4
+ from datetime import datetime
5
+ from typing import Any, Union, Dict, List, Tuple
6
+
7
+ import requests
8
+ from requests import Response
9
+ from requests.adapters import HTTPAdapter
10
+ from urllib3 import Retry
11
+
12
+ from knowledge import logger
13
+ from knowledge.services import EXPIRATION_DATE_TAG, STATUS_FORCE_LIST, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_FACTOR
14
+ from knowledge.services.base import WacomServiceAPIClient, handle_error
15
+
16
+ # -------------------------------------- Constant flags ----------------------------------------------------------------
17
+ TENANT_ID: str = "tenantId"
18
+ USER_ID_TAG: str = "userId"
19
+ LIMIT_TAG: str = "limit"
20
+ OFFSET_TAG: str = "offset"
21
+ ROLES_TAG: str = "roles"
22
+ META_DATA_TAG: str = "metadata"
23
+ INTERNAL_USER_ID_TAG: str = "internalUserId"
24
+ EXTERNAL_USER_ID_TAG: str = "externalUserId"
25
+ FORCE_TAG: str = "force"
26
+ CONTENT_TYPE_FLAG: str = "Content-Type"
27
+ TENANT_API_KEY_FLAG: str = "x-tenant-api-key"
28
+ USER_AGENT_TAG: str = "User-Agent"
29
+ DEFAULT_TIMEOUT: int = 60
30
+
31
+
32
+ class UserRole(enum.Enum):
33
+ """
34
+ UserRole
35
+ --------
36
+ Roles of the users in
37
+ """
38
+
39
+ USER = "User"
40
+ """User only has control over his personal entities."""
41
+ ADMIN = "TenantAdmin"
42
+ """TenantAdmin has access to all entities independent of the access rights."""
43
+
44
+
45
+ USER_ROLE_MAPPING: Dict[str, UserRole] = {str(r.value): r for r in UserRole}
46
+
47
+
48
+ class User:
49
+ """
50
+ User
51
+ -----
52
+ In Personal Knowledge backend is linking a user to a shadow user which is used within the personal knowledge graph.
53
+
54
+ Parameters
55
+ ----------
56
+ tenant_id: str
57
+ Tenant id
58
+ user_id: str
59
+ User id
60
+ external_user_id: str
61
+ External user id, referencing the user to authentication system.
62
+ meta_data: Dict[str, Any]
63
+ Metadata associated with user.
64
+ user_roles: List[UserRole]
65
+ List of user roles.
66
+ """
67
+
68
+ def __init__(
69
+ self, tenant_id: str, user_id: str, external_user_id: str, meta_data: Dict[str, Any], user_roles: List[UserRole]
70
+ ):
71
+ self.__tenant_id: str = tenant_id
72
+ self.__user_id: str = user_id
73
+ self.__external_user_id: str = external_user_id
74
+ self.__meta_data: Dict[str, Any] = meta_data
75
+ self.__user_roles: List[UserRole] = user_roles
76
+
77
+ @property
78
+ def id(self) -> str:
79
+ """User id."""
80
+ return self.__user_id
81
+
82
+ @property
83
+ def tenant_id(self) -> str:
84
+ """Tenant ID."""
85
+ return self.__tenant_id
86
+
87
+ @property
88
+ def external_user_id(self) -> str:
89
+ """External user id, referencing to external user authentication."""
90
+ return self.__external_user_id
91
+
92
+ @property
93
+ def meta_data(self) -> Dict[str, Any]:
94
+ """Meta data for user."""
95
+ return self.__meta_data
96
+
97
+ @meta_data.setter
98
+ def meta_data(self, value: Dict[str, Any]):
99
+ self.__meta_data = value
100
+
101
+ @property
102
+ def user_roles(self) -> List[UserRole]:
103
+ """List of user roles"""
104
+ return self.__user_roles
105
+
106
+ @classmethod
107
+ def parse(cls, param: Dict[str, Any]) -> "User":
108
+ """
109
+ Parse user from dictionary.
110
+ Parameters
111
+ ----------
112
+ param: Dict[str, Any]
113
+ Dictionary containing user information.
114
+
115
+ Returns
116
+ -------
117
+ user: User
118
+ Instance of user.
119
+ """
120
+ user_id: str = param["id"]
121
+ tenant_id: str = param[TENANT_ID]
122
+ external_user_id: str = param["externalUserId"]
123
+ meta_data: Dict[str, Any] = {}
124
+ if META_DATA_TAG in param and param[META_DATA_TAG] is not None:
125
+ meta_data = param[META_DATA_TAG]
126
+ # Support the old version of the user management service
127
+ elif "metaData" in param:
128
+ meta_data = param["metaData"]
129
+ user_roles: List[UserRole] = [USER_ROLE_MAPPING[r] for r in param["roles"]]
130
+ return User(
131
+ tenant_id=tenant_id,
132
+ user_id=user_id,
133
+ external_user_id=external_user_id,
134
+ meta_data=meta_data,
135
+ user_roles=user_roles,
136
+ )
137
+
138
+ def __repr__(self):
139
+ return f"<User: id:={self.id}, external user id:={self.external_user_id}, user roles:= {self.user_roles}]>"
140
+
141
+
142
+ class UserManagementServiceAPI(WacomServiceAPIClient):
143
+ """
144
+ User-Management Service API
145
+ -----------------------------
146
+
147
+ Functionality:
148
+ - List all users
149
+ - Create / update / delete users
150
+
151
+ Parameters
152
+ ----------
153
+ service_url: str
154
+ URL of the service
155
+ service_endpoint: str
156
+ Base endpoint
157
+ """
158
+
159
+ USER_DETAILS_ENDPOINT: str = f"{WacomServiceAPIClient.USER_ENDPOINT}/internal-id"
160
+
161
+ def __init__(self, service_url: str = WacomServiceAPIClient.SERVICE_URL, service_endpoint: str = "graph/v1"):
162
+ super().__init__("UserManagementServiceAPI", service_url=service_url, service_endpoint=service_endpoint)
163
+
164
+ # ------------------------------------------ Users handling --------------------------------------------------------
165
+
166
+ def create_user(
167
+ self,
168
+ tenant_key: str,
169
+ external_id: str,
170
+ meta_data: Dict[str, str] = None,
171
+ roles: List[UserRole] = None,
172
+ max_retries: int = DEFAULT_MAX_RETRIES,
173
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
174
+ timeout: int = DEFAULT_TIMEOUT,
175
+ ) -> Tuple[User, str, str, datetime]:
176
+ """
177
+ Creates user for a tenant.
178
+
179
+ Parameters
180
+ ----------
181
+ tenant_key: str -
182
+ API key for tenant
183
+ external_id: str -
184
+ External id of user identification service.
185
+ meta_data: Dict[str, str]
186
+ Meta-data dictionary.
187
+ roles: List[UserRole]
188
+ List of roles.
189
+ max_retries: int - [optional]
190
+ Maximum number of retries. [DEFAULT:= 3]
191
+ backoff_factor: float - [optional]
192
+ Backoff factor for retries. [DEFAULT:= 0.1]
193
+ timeout: int - [optional]
194
+ Timeout for the request. [DEFAULT:= 60]
195
+
196
+ Returns
197
+ -------
198
+ user: User
199
+ Instance of the user
200
+ token: str
201
+ Auth token for user
202
+ refresh_key: str
203
+ Refresh token
204
+ expiration_time: datetime
205
+ Expiration time
206
+ Raises
207
+ ------
208
+ WacomServiceException
209
+ If the tenant service returns an error code.
210
+ """
211
+ url: str = f"{self.service_base_url}{UserManagementServiceAPI.USER_ENDPOINT}"
212
+ headers: dict = {
213
+ USER_AGENT_TAG: self.user_agent,
214
+ TENANT_API_KEY_FLAG: tenant_key,
215
+ CONTENT_TYPE_FLAG: "application/json",
216
+ }
217
+ payload: dict = {
218
+ EXTERNAL_USER_ID_TAG: external_id,
219
+ META_DATA_TAG: meta_data if meta_data is not None else {},
220
+ ROLES_TAG: [r.value for r in roles] if roles is not None else [UserRole.USER.value],
221
+ }
222
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
223
+ with requests.Session() as session:
224
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
225
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
226
+ response: Response = session.post(
227
+ url, headers=headers, json=payload, timeout=timeout, verify=self.verify_calls
228
+ )
229
+ if response.ok:
230
+ results: Dict[str, Union[str, Dict[str, str], List[str]]] = response.json()
231
+ try:
232
+ date_object: datetime = datetime.fromisoformat(results["token"][EXPIRATION_DATE_TAG])
233
+ except (TypeError, ValueError) as _:
234
+ date_object: datetime = datetime.now()
235
+ logger.warning(f'Parsing of expiration date failed. {results["token"][EXPIRATION_DATE_TAG]}')
236
+ return (
237
+ User.parse(results["user"]),
238
+ results["token"]["accessToken"],
239
+ results["token"]["refreshToken"],
240
+ date_object,
241
+ )
242
+ raise handle_error("Failed to create user.", response)
243
+
244
+ def update_user(
245
+ self,
246
+ tenant_key: str,
247
+ internal_id: str,
248
+ external_id: str,
249
+ meta_data: Dict[str, str] = None,
250
+ roles: List[UserRole] = None,
251
+ max_retries: int = DEFAULT_MAX_RETRIES,
252
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
253
+ timeout: int = DEFAULT_TIMEOUT,
254
+ ):
255
+ """Updates user for a tenant.
256
+
257
+ Parameters
258
+ ----------
259
+ tenant_key: str
260
+ API key for tenant
261
+ internal_id: str
262
+ Internal id of semantic service.
263
+ external_id: str
264
+ External id of user identification service.
265
+ meta_data: Dict[str, str]
266
+ Meta-data dictionary.
267
+ roles: List[UserRole]
268
+ List of roles.
269
+ max_retries: int - [optional]
270
+ Maximum number of retries. [DEFAULT:= 3]
271
+ backoff_factor: float - [optional]
272
+ Backoff factor for retries. [DEFAULT:= 0.1]
273
+ timeout: int - [optional]
274
+ Timeout for the request. [DEFAULT:= 60]
275
+
276
+ Raises
277
+ ------
278
+ WacomServiceException
279
+ If the tenant service returns an error code.
280
+ """
281
+ url: str = f"{self.service_base_url}{UserManagementServiceAPI.USER_ENDPOINT}"
282
+ headers: Dict[str, str] = {
283
+ USER_AGENT_TAG: self.user_agent,
284
+ TENANT_API_KEY_FLAG: tenant_key,
285
+ CONTENT_TYPE_FLAG: "application/json",
286
+ }
287
+ payload: Dict[str, str] = {
288
+ META_DATA_TAG: meta_data if meta_data is not None else {},
289
+ ROLES_TAG: [r.value for r in roles] if roles is not None else [UserRole.USER.value],
290
+ }
291
+ params: Dict[str, str] = {USER_ID_TAG: internal_id, EXTERNAL_USER_ID_TAG: external_id}
292
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
293
+ with requests.Session() as session:
294
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
295
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
296
+ response: Response = session.patch(
297
+ url, headers=headers, json=payload, params=params, timeout=timeout, verify=self.verify_calls
298
+ )
299
+ if not response.ok:
300
+ raise handle_error("Updating of user failed.", response)
301
+
302
+ def delete_user(
303
+ self,
304
+ tenant_key: str,
305
+ external_id: str,
306
+ internal_id: str,
307
+ force: bool = False,
308
+ max_retries: int = DEFAULT_MAX_RETRIES,
309
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
310
+ timeout: int = DEFAULT_TIMEOUT,
311
+ ):
312
+ """Deletes user from tenant.
313
+
314
+ Parameters
315
+ ----------
316
+ tenant_key: str
317
+ API key for tenant
318
+ external_id: str
319
+ External id of user identification service.
320
+ internal_id: str
321
+ Internal id of user.
322
+ force: bool
323
+ If set to true removes all user data including groups and entities.
324
+ max_retries: int - [optional]
325
+ Maximum number of retries. [DEFAULT:= 3]
326
+ backoff_factor: float - [optional]
327
+ Backoff factor for retries. [DEFAULT:= 0.1]
328
+ timeout: int - [optional]
329
+ Timeout for the request. [DEFAULT:= 60]
330
+
331
+ Raises
332
+ ------
333
+ WacomServiceException
334
+ If the tenant service returns an error code.
335
+ """
336
+ url: str = f"{self.service_base_url}{UserManagementServiceAPI.USER_ENDPOINT}"
337
+ headers: Dict[str, str] = {USER_AGENT_TAG: self.user_agent, TENANT_API_KEY_FLAG: tenant_key}
338
+ params: Dict[str, str] = {USER_ID_TAG: internal_id, EXTERNAL_USER_ID_TAG: external_id, FORCE_TAG: force}
339
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
340
+ with requests.Session() as session:
341
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
342
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
343
+ response: Response = session.delete(
344
+ url, headers=headers, params=params, timeout=timeout, verify=self.verify_calls
345
+ )
346
+ if not response.ok:
347
+ raise handle_error("Deletion of user failed.", response)
348
+
349
+ def user_internal_id(
350
+ self,
351
+ tenant_key: str,
352
+ external_id: str,
353
+ max_retries: int = DEFAULT_MAX_RETRIES,
354
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
355
+ timeout: int = DEFAULT_TIMEOUT,
356
+ ) -> str:
357
+ """User internal id.
358
+
359
+ Parameters
360
+ ----------
361
+ tenant_key: str
362
+ API key for tenant
363
+ external_id: str
364
+ External id of user
365
+ max_retries: int - [optional]
366
+ Maximum number of retries. [DEFAULT:= 3]
367
+ backoff_factor: float - [optional]
368
+ Backoff factor for retries. [DEFAULT:= 0.1]
369
+ timeout: int - [optional]
370
+ Timeout for the request. [DEFAULT:= 60]
371
+
372
+ Returns
373
+ -------
374
+ internal_user_id: str
375
+ Internal id of users
376
+
377
+ Raises
378
+ ------
379
+ WacomServiceException
380
+ If the tenant service returns an error code.
381
+ """
382
+ url: str = f"{self.service_base_url}{UserManagementServiceAPI.USER_DETAILS_ENDPOINT}"
383
+ headers: dict = {USER_AGENT_TAG: self.user_agent, TENANT_API_KEY_FLAG: tenant_key}
384
+ parameters: Dict[str, str] = {EXTERNAL_USER_ID_TAG: external_id}
385
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
386
+ with requests.Session() as session:
387
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
388
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
389
+ response: Response = session.get(
390
+ url, headers=headers, params=parameters, timeout=timeout, verify=self.verify_calls
391
+ )
392
+ if response.ok:
393
+ response_dict: Dict[str, Any] = response.json()
394
+ return response_dict[INTERNAL_USER_ID_TAG]
395
+ raise handle_error("Retrieval of user internal id failed.", response)
396
+
397
+ def listing_users(
398
+ self,
399
+ tenant_key: str,
400
+ offset: int = 0,
401
+ limit: int = 20,
402
+ max_retries: int = DEFAULT_MAX_RETRIES,
403
+ backoff_factor: float = DEFAULT_BACKOFF_FACTOR,
404
+ timeout: int = DEFAULT_TIMEOUT,
405
+ ) -> List[User]:
406
+ """
407
+ Listing all users configured for this instance.
408
+
409
+ Parameters
410
+ ----------
411
+ tenant_key: str
412
+ API key for tenant
413
+ offset: int - [optional]
414
+ Offset value to define starting position in list. [DEFAULT:= 0]
415
+ limit: int - [optional]
416
+ Define the limit of the list size. [DEFAULT:= 20]
417
+ max_retries: int - [optional]
418
+ Maximum number of retries. [DEFAULT:= 3]
419
+ backoff_factor: float - [optional]
420
+ Backoff factor for retries. [DEFAULT:= 0.1]
421
+ timeout: int - [optional]
422
+ Timeout for the request. [DEFAULT:= 60]
423
+
424
+ Returns
425
+ -------
426
+ user: List[User]
427
+ List of users.
428
+ """
429
+ url: str = f"{self.service_base_url}{UserManagementServiceAPI.USER_ENDPOINT}"
430
+ headers: Dict[str, str] = {USER_AGENT_TAG: self.user_agent, TENANT_API_KEY_FLAG: tenant_key}
431
+ params: Dict[str, str] = {OFFSET_TAG: offset, LIMIT_TAG: limit}
432
+ mount_point: str = "https://" if self.service_url.startswith("https") else "http://"
433
+ with requests.Session() as session:
434
+ retries: Retry = Retry(total=max_retries, backoff_factor=backoff_factor, status_forcelist=STATUS_FORCE_LIST)
435
+ session.mount(mount_point, HTTPAdapter(max_retries=retries))
436
+ response: Response = session.get(
437
+ url, headers=headers, params=params, timeout=timeout, verify=self.verify_calls
438
+ )
439
+ if response.ok:
440
+ users: List[Dict[str, Any]] = response.json()
441
+ results: List[User] = []
442
+ for u in users:
443
+ results.append(User.parse(u))
444
+ return results
445
+ raise handle_error("Listing of users failed.", response)
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright © 2024-present Wacom. All rights reserved.
3
+ """ "Utilities"""
4
+
5
+ __all__ = ["wikipedia", "graph", "wikidata"]
6
+
7
+
8
+ from knowledge.utils import wikipedia
9
+ from knowledge.utils import graph
10
+ from knowledge.utils import wikidata