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,417 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright © 2024-present Wacom. All rights reserved.
3
+ from typing import Optional, Iterator, Tuple, AsyncIterator
4
+
5
+ from knowledge.base.language import LocaleCode
6
+ from knowledge.base.ontology import OntologyClassReference, ThingObject
7
+ from knowledge.services.asyncio.graph import AsyncWacomKnowledgeService
8
+ from knowledge.services.graph import WacomKnowledgeService, Visibility
9
+
10
+
11
+ def count_things(
12
+ wacom_client: WacomKnowledgeService,
13
+ user_token: str,
14
+ concept_type: OntologyClassReference,
15
+ locale: Optional[LocaleCode] = None,
16
+ visibility: Optional[Visibility] = None,
17
+ only_own: Optional[bool] = None,
18
+ ) -> int:
19
+ """
20
+ Counts the number of things.
21
+
22
+ Parameters
23
+ ----------
24
+ wacom_client: WacomKnowledgeService
25
+ The Wacom Knowledge Service
26
+ user_token: str
27
+ The user token
28
+ concept_type: OntologyClassReference
29
+ The concept type
30
+ locale: Optional[LocaleCode]
31
+ The locale
32
+ visibility: Optional[Visibility]
33
+ The visibility
34
+ only_own: Optional[bool]
35
+ Only own things
36
+ Returns
37
+ -------
38
+ int
39
+ The number of things
40
+ """
41
+ _, total, _ = wacom_client.listing(
42
+ concept_type,
43
+ visibility=visibility,
44
+ locale=locale,
45
+ is_owner=only_own,
46
+ limit=1,
47
+ estimate_count=True,
48
+ auth_key=user_token,
49
+ )
50
+ return total
51
+
52
+
53
+ def count_things_session(
54
+ wacom_client: WacomKnowledgeService,
55
+ concept_type: OntologyClassReference,
56
+ locale: Optional[LocaleCode] = None,
57
+ visibility: Optional[Visibility] = None,
58
+ only_own: Optional[bool] = None,
59
+ ) -> int:
60
+ """
61
+ Counts the number of things.
62
+
63
+ Parameters
64
+ ----------
65
+ wacom_client: WacomKnowledgeService
66
+ The Wacom Knowledge Service
67
+ concept_type: OntologyClassReference
68
+ The concept type
69
+ locale: Optional[LocaleCode]
70
+ The locale
71
+ visibility: Optional[Visibility]
72
+ The visibility
73
+ only_own: Optional[bool]
74
+ Only own things
75
+ Returns
76
+ -------
77
+ int
78
+ The number of things
79
+ """
80
+ _, total, _ = wacom_client.listing(
81
+ concept_type, visibility=visibility, locale=locale, is_owner=only_own, limit=1, estimate_count=True
82
+ )
83
+ return total
84
+
85
+
86
+ def things_session_iter(
87
+ wacom_client: WacomKnowledgeService,
88
+ concept_type: OntologyClassReference,
89
+ visibility: Optional[Visibility] = None,
90
+ locale: Optional[LocaleCode] = None,
91
+ only_own: bool = False,
92
+ fetch_size: int = 100,
93
+ force_refresh_timeout: int = 360,
94
+ ) -> Iterator[ThingObject]:
95
+ """
96
+ Iterates over all things using the current session configured for client.
97
+
98
+ Parameters
99
+ ----------
100
+ wacom_client: WacomKnowledgeService
101
+ The Wacom Knowledge Service
102
+ concept_type: OntologyClassReference
103
+ The class type
104
+ visibility: Optional[Visibility] [default:= None]
105
+ The visibility
106
+ locale: Optional[LocaleCode] [default:= None]
107
+ Only entities with this labels having a given locale
108
+ only_own: bool [default:= False]
109
+ Only own things
110
+ fetch_size: int [default:= 100]
111
+ Fetch size.
112
+ force_refresh_timeout: int [default:= 360]
113
+ Force refresh timeout
114
+
115
+ Returns
116
+ -------
117
+ Iterator[ThingObject]
118
+ Iterator of things
119
+
120
+ Raises
121
+ ------
122
+ ValueError
123
+ If no session is configured for client
124
+ """
125
+ next_page_id: Optional[str] = None
126
+ if wacom_client.current_session is None:
127
+ raise ValueError("No session configured for client")
128
+ while True:
129
+ # Refresh token if needed
130
+ things, _, next_page_id = wacom_client.listing(
131
+ concept_type,
132
+ visibility=visibility,
133
+ locale=locale,
134
+ is_owner=only_own,
135
+ limit=fetch_size,
136
+ page_id=next_page_id,
137
+ )
138
+ if len(things) == 0:
139
+ return
140
+ for obj in things:
141
+ # Refresh token if needed
142
+ wacom_client.handle_token(force_refresh_timeout=force_refresh_timeout)
143
+ yield obj
144
+
145
+
146
+ def things_iter(
147
+ wacom_client: WacomKnowledgeService,
148
+ user_token: str,
149
+ refresh_token: str,
150
+ concept_type: OntologyClassReference,
151
+ visibility: Optional[Visibility] = None,
152
+ locale: Optional[LocaleCode] = None,
153
+ only_own: bool = False,
154
+ fetch_size: int = 100,
155
+ force_refresh_timeout: int = 360,
156
+ tenant_api_key: Optional[str] = None,
157
+ external_user_id: Optional[str] = None,
158
+ ) -> Iterator[Tuple[ThingObject, str, str]]:
159
+ """
160
+ Iterates over all things.
161
+
162
+ Parameters
163
+ ----------
164
+ wacom_client: WacomKnowledgeService
165
+ The Wacom Knowledge Service
166
+ user_token: str
167
+ The user token
168
+ refresh_token: str
169
+ The refresh token
170
+ concept_type: OntologyClassReference
171
+ The class type
172
+ visibility: Optional[Visibility] [default:= None]
173
+ The visibility
174
+ locale: Optional[LocaleCode] [default:= None]
175
+ Only entities with this labels having a given locale
176
+ only_own: bool [default:= False]
177
+ Only own things
178
+ fetch_size: int [default:= 100]
179
+ Fetch size.
180
+ force_refresh_timeout: int [default:= 360]
181
+ Force refresh timeout
182
+ tenant_api_key: Optional[str] [default:= None]
183
+ The tenant API key
184
+ external_user_id: Optional[str] [default:= None]
185
+ The external user ID
186
+
187
+ Yields
188
+ -------
189
+ obj: ThingObject
190
+ Current thing
191
+ user_token: str
192
+ The user token
193
+ refresh_token: str
194
+ The refresh token
195
+ """
196
+ next_page_id: Optional[str] = None
197
+ if tenant_api_key is not None and external_user_id is not None:
198
+ # First login
199
+ wacom_client.login(tenant_api_key=tenant_api_key, external_user_id=external_user_id)
200
+ else:
201
+ wacom_client.register_token(user_token, refresh_token)
202
+ while True:
203
+ # Refresh token if needed
204
+ things, _, next_page_id = wacom_client.listing(
205
+ concept_type,
206
+ visibility=visibility,
207
+ locale=locale,
208
+ is_owner=only_own,
209
+ limit=fetch_size,
210
+ page_id=next_page_id,
211
+ )
212
+ if len(things) == 0:
213
+ return
214
+ for obj in things:
215
+ # Refresh token if needed
216
+ wacom_client.handle_token(force_refresh_timeout=force_refresh_timeout)
217
+ yield obj, user_token, refresh_token
218
+
219
+
220
+ async def async_count_things(
221
+ async_client: AsyncWacomKnowledgeService,
222
+ user_token: str,
223
+ concept_type: OntologyClassReference,
224
+ locale: Optional[LocaleCode] = None,
225
+ visibility: Optional[Visibility] = None,
226
+ only_own: Optional[bool] = None,
227
+ ) -> int:
228
+ """
229
+ Async counting of things given a concept type.
230
+
231
+ Parameters
232
+ ----------
233
+ async_client: AsyncWacomKnowledgeService
234
+ The Wacom Knowledge Service
235
+ user_token: str
236
+ The user token
237
+ concept_type: OntologyClassReference
238
+ The concept type
239
+ locale: Optional[LocaleCode]
240
+ The locale
241
+ visibility: Optional[Visibility]
242
+ The visibility
243
+ only_own: Optional[bool]
244
+ Only own things
245
+
246
+ Returns
247
+ -------
248
+ int
249
+ The number of things
250
+ """
251
+ _, total, _ = await async_client.listing(
252
+ concept_type,
253
+ visibility=visibility,
254
+ locale=locale,
255
+ limit=1,
256
+ estimate_count=True,
257
+ is_owner=only_own,
258
+ auth_key=user_token,
259
+ )
260
+ return total
261
+
262
+
263
+ async def async_count_things_session(
264
+ async_client: AsyncWacomKnowledgeService,
265
+ concept_type: OntologyClassReference,
266
+ locale: Optional[LocaleCode] = None,
267
+ visibility: Optional[Visibility] = None,
268
+ only_own: Optional[bool] = None,
269
+ ) -> int:
270
+ """
271
+ Async counting of things given a concept type using session.
272
+
273
+ Parameters
274
+ ----------
275
+ async_client: AsyncWacomKnowledgeService
276
+ The Wacom Knowledge Service
277
+ concept_type: OntologyClassReference
278
+ The concept type
279
+ locale: Optional[LocaleCode]
280
+ The locale
281
+ visibility: Optional[Visibility]
282
+ The visibility
283
+ only_own: Optional[bool]
284
+ Only own things
285
+
286
+ Returns
287
+ -------
288
+ int
289
+ The number of things
290
+ """
291
+ _, total, _ = await async_client.listing(
292
+ concept_type, visibility=visibility, is_owner=only_own, locale=locale, limit=1, estimate_count=True
293
+ )
294
+ return total
295
+
296
+
297
+ async def async_things_iter(
298
+ async_client: AsyncWacomKnowledgeService,
299
+ user_token: str,
300
+ refresh_token: str,
301
+ concept_type: OntologyClassReference,
302
+ visibility: Optional[Visibility] = None,
303
+ locale: Optional[LocaleCode] = None,
304
+ only_own: Optional[bool] = None,
305
+ fetch_size: int = 100,
306
+ force_refresh_timeout: int = 360,
307
+ tenant_api_key: Optional[str] = None,
308
+ external_user_id: Optional[str] = None,
309
+ ) -> AsyncIterator[Tuple[ThingObject, str, str]]:
310
+ """
311
+ Asynchronous iterator over all things of a given type.
312
+
313
+ Parameters
314
+ ----------
315
+ async_client: AsyncWacomKnowledgeService
316
+ The Wacom Knowledge Service
317
+ user_token: str
318
+ The user token
319
+ refresh_token: str
320
+ The refresh token
321
+ concept_type: OntologyClassReference
322
+ The class type
323
+ visibility: Optional[Visibility] [default:= None]
324
+ The visibility
325
+ locale: Optional[LocaleCode] [default:= None]
326
+ Only entities with this labels having a given locale
327
+ only_own: Optional[bool] = [default:= None]
328
+ Only own things
329
+ fetch_size: int [default:= 100]
330
+ Fetch size.
331
+ force_refresh_timeout: int [default:= 360]
332
+ Force refresh timeout
333
+ tenant_api_key: Optional[str] [default:= None]
334
+ The tenant API key
335
+ external_user_id: Optional[str] [default:= None]
336
+ The external user ID
337
+
338
+ Returns
339
+ -------
340
+ AsyncIterator[ThingObject]
341
+ Asynchronous Iterator of things
342
+ """
343
+ next_page_id: Optional[str] = None
344
+ if tenant_api_key is not None and external_user_id is not None:
345
+ # First login
346
+ await async_client.login(tenant_api_key=tenant_api_key, external_user_id=external_user_id)
347
+ else:
348
+ await async_client.register_token(user_token, refresh_token)
349
+ while True:
350
+ things, _, next_page_id = await async_client.listing(
351
+ concept_type,
352
+ visibility=visibility,
353
+ locale=locale,
354
+ is_owner=only_own,
355
+ limit=fetch_size,
356
+ page_id=next_page_id,
357
+ )
358
+ if len(things) == 0:
359
+ return
360
+ for obj in things:
361
+ user_token, refresh_token = await async_client.handle_token(force_refresh_timeout=force_refresh_timeout)
362
+ yield obj, user_token, refresh_token
363
+
364
+
365
+ async def async_things_session_iter(
366
+ async_client: AsyncWacomKnowledgeService,
367
+ concept_type: OntologyClassReference,
368
+ visibility: Optional[Visibility] = None,
369
+ locale: Optional[LocaleCode] = None,
370
+ only_own: Optional[bool] = None,
371
+ fetch_size: int = 100,
372
+ force_refresh_timeout: int = 360,
373
+ ) -> AsyncIterator[ThingObject]:
374
+ """
375
+ Asynchronous iterator over all things of a given type using session.
376
+
377
+ Parameters
378
+ ----------
379
+ async_client: AsyncWacomKnowledgeService
380
+ The Wacom Knowledge Service
381
+ concept_type: OntologyClassReference
382
+ The class type
383
+ visibility: Optional[Visibility] [default:= None]
384
+ The visibility
385
+ locale: Optional[LocaleCode] [default:= None]
386
+ Only entities with this labels having a given locale
387
+ only_own: Optional[bool] = [default:= None]
388
+ Only own things
389
+ fetch_size: int [default:= 100]
390
+ Fetch size.
391
+ force_refresh_timeout: int [default:= 360]
392
+ Force refresh timeout
393
+
394
+ Returns
395
+ -------
396
+ AsyncIterator[ThingObject]
397
+ Asynchronous Iterator of things
398
+ """
399
+ next_page_id: Optional[str] = None
400
+ if async_client.current_session is None:
401
+ raise ValueError("No session configured for client")
402
+
403
+ while True:
404
+ things, _, next_page_id = await async_client.listing(
405
+ concept_type,
406
+ visibility=visibility,
407
+ is_owner=only_own,
408
+ locale=locale,
409
+ limit=fetch_size,
410
+ page_id=next_page_id,
411
+ )
412
+ if len(things) == 0:
413
+ return
414
+ for obj in things:
415
+ await async_client.handle_token(force_refresh_timeout=force_refresh_timeout)
416
+ if obj.owner or not only_own:
417
+ yield obj
@@ -0,0 +1,197 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright © 2024-present Wacom. All rights reserved.
3
+ from typing import Any, Dict, List
4
+
5
+ from knowledge import logger
6
+ from knowledge.base.entity import LanguageCode, IMAGE_TAG, STATUS_FLAG_TAG, Description, Label
7
+ from knowledge.base.language import LANGUAGE_LOCALE_MAPPING, LocaleCode
8
+ from knowledge.base.ontology import ThingObject, OntologyClassReference
9
+
10
+
11
+ # ----------------------------------------------- Helper functions -----------------------------------------------------
12
+ def update_language_code(lang: LanguageCode) -> LocaleCode:
13
+ """Update the language_code code to a default language_code / country code
14
+ Parameters
15
+ ----------
16
+ lang: LanguageCode
17
+ Language code.
18
+
19
+ Returns
20
+ -------
21
+ language_code: LocaleCode
22
+ Language code.
23
+
24
+ Raises
25
+ ------
26
+ ValueError
27
+ If the language_code code is not supported.
28
+ """
29
+ if lang not in LANGUAGE_LOCALE_MAPPING:
30
+ raise ValueError(f"Language code {lang} not supported.")
31
+ return LANGUAGE_LOCALE_MAPPING[lang]
32
+
33
+
34
+ def localized_list_description(entity_dict: Dict[str, str]) -> List[Description]:
35
+ """
36
+ Creates a list of descriptions for the given entity dictionary.
37
+ Parameters
38
+ ----------
39
+ entity_dict: Dict[str, str]
40
+ Entities dictionary.
41
+
42
+ Returns
43
+ -------
44
+ descriptions: List[Description]
45
+ List of descriptions.
46
+ """
47
+ return [Description(cont, update_language_code(LanguageCode(lang))) for lang, cont in entity_dict.items()]
48
+
49
+
50
+ def localized_list_label(entity_dict: Dict[str, str]) -> List[Label]:
51
+ """
52
+ Creates a list of labels for the given entity dictionary.
53
+
54
+ Parameters
55
+ ----------
56
+ entity_dict: Dict[str, str]
57
+ Entities dictionary.
58
+
59
+ Returns
60
+ -------
61
+ labels: List[Label]
62
+ List of labels.
63
+ """
64
+ return [
65
+ Label(cont, update_language_code(LanguageCode(lang)), main=True)
66
+ for lang, cont in entity_dict.items()
67
+ if cont != ""
68
+ ]
69
+
70
+
71
+ def localized_flatten_alias_list(entity_dict: Dict[str, List[str]]) -> List[Label]:
72
+ """
73
+ Flattens the alias list.
74
+ Parameters
75
+ ----------
76
+ entity_dict: Dict[str, List[str]]
77
+ Entities dictionary.
78
+
79
+ Returns
80
+ -------
81
+ flatten: List[Label]
82
+ Flattened list of labels.
83
+ """
84
+ flatten: List[Label] = []
85
+ for language, items in entity_dict.items():
86
+ for i in items:
87
+ if i != "":
88
+ flatten.append(Label(i, update_language_code(LanguageCode(language)), main=False))
89
+ return flatten
90
+
91
+
92
+ def from_dict(entity: Dict[str, Any], concept_type: OntologyClassReference) -> ThingObject:
93
+ """
94
+ Create a thing object from a dictionary.
95
+ Parameters
96
+ ----------
97
+ entity: Dict[str, Any]
98
+ Entities dictionary.
99
+ concept_type: OntologyClassReference
100
+ Concept type.
101
+
102
+ Returns
103
+ -------
104
+ thing: ThingObject
105
+ Thing object.
106
+ """
107
+ labels: List[Label] = localized_list_label(entity["label"])
108
+ description: List[Description] = localized_list_description(entity["description"])
109
+ alias: List[Label] = localized_flatten_alias_list(entity["alias"])
110
+ if IMAGE_TAG in entity:
111
+ icon: str = entity[IMAGE_TAG]
112
+ else:
113
+ logger.warning(f"Entity has no image: {entity}")
114
+ icon: str = ""
115
+ # Create the entity
116
+ thing: ThingObject = ThingObject(label=labels, concept_type=concept_type, description=description, icon=icon)
117
+ thing.alias = alias
118
+ if STATUS_FLAG_TAG in entity:
119
+ thing.status_flag = entity[STATUS_FLAG_TAG]
120
+ return thing
121
+
122
+
123
+ # --------------------------------------------------- Utilities --------------------------------------------------------
124
+
125
+
126
+ def strip(url: str) -> str:
127
+ """Strip qid from url.
128
+ Parameters
129
+ ----------
130
+ url: str
131
+ URL
132
+ Returns
133
+ -------
134
+ result: str
135
+ Stripped URL
136
+ """
137
+ parts = url.split("/")
138
+ return parts[-1]
139
+
140
+
141
+ def build_query(params: Dict[str, Any]) -> List[str]:
142
+ """
143
+ Build of query.
144
+
145
+ Parameters
146
+ ----------
147
+ params:
148
+ Parameters for query
149
+
150
+ Returns
151
+ -------
152
+ queries: List[str]
153
+ SPARQL query string
154
+ """
155
+ filters: List[Dict[str, Any]] = params.get("filters")
156
+ dynamics: Dict[str, Any] = params.get("dynamic-filters")
157
+ limit: int = params.get("limit", 1000)
158
+ lang_code: str = params.get("language_code", "en")
159
+ filter_string: str = ""
160
+ queries: List[str] = []
161
+ for f in filters:
162
+ filter_string += f"?item wdt:{f['property']} wd:{f['target']}.\n"
163
+ if dynamics:
164
+ property_str: str = dynamics["property"]
165
+ for v in dynamics["targets"]:
166
+ dyn: str = filter_string + f"?item wdt:{property_str} wd:{v}.\n"
167
+ query: str = f"""SELECT DISTINCT ?item ?itemLabel WHERE {{
168
+ {dyn}SERVICE wikibase:label {{ bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],{lang_code}\". }}
169
+ }}
170
+ LIMIT {limit}
171
+ """
172
+ queries.append(query)
173
+ else:
174
+ query: str = f"""SELECT DISTINCT ?item ?itemLabel WHERE {{
175
+ {filter_string}SERVICE wikibase:label {{ bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],{lang_code}\". }}
176
+ }}
177
+ LIMIT {limit}
178
+ """
179
+ queries.append(query)
180
+ return queries
181
+
182
+
183
+ def extract_qid(url: str) -> str:
184
+ """
185
+ Extract qid from url.
186
+ Parameters
187
+ ----------
188
+ url: str
189
+ URL
190
+
191
+ Returns
192
+ -------
193
+ qid: str
194
+ QID
195
+ """
196
+ parts: List[str] = url.split("/")
197
+ return parts[-1]